00001 #include <net-snmp/net-snmp-config.h>
00002
00003 #ifdef NETSNMP_TRANSPORT_TCPIPV6_DOMAIN
00004
00005
00006
00007
00008 #if defined(cygwin)
00009 #undef HAVE_UNISTD_H
00010 #undef HAVE_NETINET_IN_H
00011 #undef HAVE_ARPA_INET_H
00012 #undef HAVE_NET_IF_H
00013 #undef HAVE_NETDB_H
00014 #undef HAVE_SYS_PARAM_H
00015 #undef HAVE_SYS_SELECT_H
00016 #undef HAVE_SYS_SOCKET_H
00017 #undef HAVE_IN_ADDR_T
00018 #endif
00019
00020 #include <stdio.h>
00021 #include <sys/types.h>
00022 #include <errno.h>
00023
00024 #if HAVE_STRING_H
00025 #include <string.h>
00026 #else
00027 #include <strings.h>
00028 #endif
00029 #if HAVE_STDLIB_H
00030 #include <stdlib.h>
00031 #endif
00032 #if HAVE_UNISTD_H
00033 #include <unistd.h>
00034 #endif
00035 #if HAVE_SYS_SOCKET_H
00036 #include <sys/socket.h>
00037 #endif
00038
00039 #if defined(HAVE_WINSOCK_H) || defined(cygwin)
00040
00041
00042
00043 #include <winsock2.h>
00044 #include <ws2tcpip.h>
00045
00046 #ifndef HAVE_INET_NTOP
00047 extern const char *inet_ntop(int, const void*, char*, size_t);
00048 #endif
00049
00050 #endif
00051
00052 #if HAVE_NETINET_IN_H
00053 #include <netinet/in.h>
00054 #endif
00055 #if HAVE_ARPA_INET_H
00056 #include <arpa/inet.h>
00057 #endif
00058 #if HAVE_NETDB_H
00059 #include <netdb.h>
00060 #endif
00061 #if HAVE_FCNTL_H
00062 #include <fcntl.h>
00063 #endif
00064
00065 #if HAVE_DMALLOC_H
00066 #include <dmalloc.h>
00067 #endif
00068
00069 #include <net-snmp/types.h>
00070 #include <net-snmp/output_api.h>
00071 #include <net-snmp/config_api.h>
00072
00073 #include <net-snmp/library/snmp_transport.h>
00074 #include <net-snmp/library/snmpUDPDomain.h>
00075 #include <net-snmp/library/snmpUDPIPv6Domain.h>
00076 #include <net-snmp/library/snmpTCPIPv6Domain.h>
00077
00078 oid netsnmp_TCPIPv6Domain[] = { TRANSPORT_DOMAIN_TCP_IPV6 };
00079 static netsnmp_tdomain tcp6Domain;
00080
00081
00082
00083
00084
00085
00086 static char *
00087 netsnmp_tcp6_fmtaddr(netsnmp_transport *t, void *data, int len)
00088 {
00089 struct sockaddr_in6 *to = NULL;
00090
00091 DEBUGMSGTL(("netsnmp_tcp6", "fmtaddr: t = %p, data = %p, len = %d\n", t,
00092 data, len));
00093 if (data != NULL && len == sizeof(struct sockaddr_in6)) {
00094 to = (struct sockaddr_in6 *) data;
00095 } else if (t != NULL && t->data != NULL) {
00096 to = (struct sockaddr_in6 *) t->data;
00097 }
00098 if (to == NULL) {
00099 return strdup("TCP/IPv6: unknown");
00100 } else {
00101 char addr[INET6_ADDRSTRLEN];
00102 char tmp[INET6_ADDRSTRLEN + 18];
00103
00104 sprintf(tmp, "TCP/IPv6: [%s]:%hu",
00105 inet_ntop(AF_INET6, (void *) &(to->sin6_addr), addr,
00106 INET6_ADDRSTRLEN), ntohs(to->sin6_port));
00107 return strdup(tmp);
00108 }
00109 }
00110
00111
00112
00113
00114
00115
00116
00117 static int
00118 netsnmp_tcp6_recv(netsnmp_transport *t, void *buf, int size,
00119 void **opaque, int *olength)
00120 {
00121 int rc = -1;
00122
00123 if (t != NULL && t->sock >= 0) {
00124 while (rc < 0) {
00125 rc = recvfrom(t->sock, buf, size, 0, NULL, NULL);
00126 if (rc < 0 && errno != EINTR) {
00127 DEBUGMSGTL(("netsnmp_tcp6", "recv fd %d err %d (\"%s\")\n",
00128 t->sock, errno, strerror(errno)));
00129 return -1;
00130 }
00131 }
00132 DEBUGMSGTL(("netsnmp_tcp6", "recv fd %d got %d bytes\n", t->sock, rc));
00133 } else {
00134 return -1;
00135 }
00136
00137 if (opaque != NULL && olength != NULL) {
00138 if (t->data_length > 0) {
00139 if ((*opaque = malloc(t->data_length)) != NULL) {
00140 memcpy(*opaque, t->data, t->data_length);
00141 *olength = t->data_length;
00142 } else {
00143 *olength = 0;
00144 }
00145 } else {
00146 *opaque = NULL;
00147 *olength = 0;
00148 }
00149 }
00150
00151 return rc;
00152 }
00153
00154 static int
00155 netsnmp_tcp6_send(netsnmp_transport *t, void *buf, int size,
00156 void **opaque, int *olength)
00157 {
00158 int rc = -1;
00159
00160 if (t != NULL && t->sock >= 0) {
00161 while (rc < 0) {
00162 rc = sendto(t->sock, buf, size, 0, NULL, 0);
00163 if (rc < 0 && errno != EINTR) {
00164 break;
00165 }
00166 }
00167 }
00168 return rc;
00169 }
00170
00171 static int
00172 netsnmp_tcp6_close(netsnmp_transport *t)
00173 {
00174 int rc = -1;
00175 if (t != NULL && t->sock >= 0) {
00176 DEBUGMSGTL(("netsnmp_tcp6", "close fd %d\n", t->sock));
00177 #ifndef HAVE_CLOSESOCKET
00178 rc = close(t->sock);
00179 #else
00180 rc = closesocket(t->sock);
00181 #endif
00182 t->sock = -1;
00183 }
00184 return rc;
00185 }
00186
00187 static int
00188 netsnmp_tcp6_accept(netsnmp_transport *t)
00189 {
00190 struct sockaddr_in6 *farend = NULL;
00191 int newsock = -1, sockflags = 0;
00192 socklen_t farendlen = sizeof(struct sockaddr_in6);
00193 char *str = NULL;
00194
00195 farend = (struct sockaddr_in6 *) malloc(sizeof(struct sockaddr_in6));
00196
00197 if (farend == NULL) {
00198
00199
00200
00201 DEBUGMSGTL(("netsnmp_tcp6", "accept: malloc failed\n"));
00202 return -1;
00203 }
00204
00205 if (t != NULL && t->sock >= 0) {
00206 newsock = accept(t->sock, (struct sockaddr *) farend, &farendlen);
00207
00208 if (newsock < 0) {
00209 DEBUGMSGTL(("netsnmp_tcp6","accept failed rc %d errno %d \"%s\"\n",
00210 newsock, errno, strerror(errno)));
00211 free(farend);
00212 return newsock;
00213 }
00214
00215 if (t->data != NULL) {
00216 free(t->data);
00217 }
00218
00219 t->data = farend;
00220 t->data_length = farendlen;
00221 str = netsnmp_tcp6_fmtaddr(NULL, farend, farendlen);
00222 DEBUGMSGTL(("netsnmp_tcp6", "accept succeeded (from %s)\n", str));
00223 free(str);
00224
00225
00226
00227
00228
00229 #ifdef WIN32
00230 ioctlsocket(newsock, FIONBIO, &sockflags);
00231 #else
00232 if ((sockflags = fcntl(newsock, F_GETFL, 0)) >= 0) {
00233 fcntl(newsock, F_SETFL, (sockflags & ~O_NONBLOCK));
00234 } else {
00235 DEBUGMSGTL(("netsnmp_tcp6", "accept: couldn't f_getfl of fd %d\n",
00236 newsock));
00237 }
00238 #endif
00239
00240
00241
00242
00243
00244
00245 netsnmp_sock_buffer_set(newsock, SO_SNDBUF, 1, 0);
00246 netsnmp_sock_buffer_set(newsock, SO_RCVBUF, 1, 0);
00247
00248 return newsock;
00249 } else {
00250 free(farend);
00251 return -1;
00252 }
00253 }
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 netsnmp_transport *
00264 netsnmp_tcp6_transport(struct sockaddr_in6 *addr, int local)
00265 {
00266 netsnmp_transport *t = NULL;
00267 int rc = 0;
00268 char *str = NULL;
00269
00270 if (addr == NULL || addr->sin6_family != AF_INET6) {
00271 return NULL;
00272 }
00273
00274 t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
00275 if (t == NULL) {
00276 return NULL;
00277 }
00278 memset(t, 0, sizeof(netsnmp_transport));
00279
00280 str = netsnmp_tcp6_fmtaddr(NULL, (void *)addr,
00281 sizeof(struct sockaddr_in6));
00282 DEBUGMSGTL(("netsnmp_tcp6", "open %s %s\n", local ? "local" : "remote",
00283 str));
00284 free(str);
00285
00286 memset(t, 0, sizeof(netsnmp_transport));
00287
00288 t->data = malloc(sizeof(struct sockaddr_in6));
00289 if (t->data == NULL) {
00290 netsnmp_transport_free(t);
00291 return NULL;
00292 }
00293 t->data_length = sizeof(struct sockaddr_in6);
00294 memcpy(t->data, addr, sizeof(struct sockaddr_in6));
00295
00296 t->domain = netsnmp_TCPIPv6Domain;
00297 t->domain_length = sizeof(netsnmp_TCPIPv6Domain) / sizeof(oid);
00298
00299 t->sock = socket(PF_INET6, SOCK_STREAM, 0);
00300 if (t->sock < 0) {
00301 netsnmp_transport_free(t);
00302 return NULL;
00303 }
00304
00305 t->flags = NETSNMP_TRANSPORT_FLAG_STREAM;
00306
00307 if (local) {
00308 int sockflags = 0, opt = 1;
00309
00310
00311
00312
00313
00314
00315
00316 #ifdef IPV6_V6ONLY
00317
00318 {
00319 int one=1;
00320 if (setsockopt(t->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) != 0) {
00321 DEBUGMSGTL(("netsnmp_udp6", "couldn't set IPV6_V6ONLY to %d bytes: %s\n", one, strerror(errno)));
00322 }
00323 }
00324 #endif
00325
00326 t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN;
00327 t->local = (unsigned char*)malloc(18);
00328 if (t->local == NULL) {
00329 netsnmp_tcp6_close(t);
00330 netsnmp_transport_free(t);
00331 return NULL;
00332 }
00333 memcpy(t->local, addr->sin6_addr.s6_addr, 16);
00334 t->local[16] = (addr->sin6_port & 0xff00) >> 8;
00335 t->local[17] = (addr->sin6_port & 0x00ff) >> 0;
00336 t->local_length = 18;
00337
00338
00339
00340
00341
00342 setsockopt(t->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt));
00343
00344 rc = bind(t->sock, (struct sockaddr *) addr,
00345 sizeof(struct sockaddr_in6));
00346 if (rc != 0) {
00347 netsnmp_tcp6_close(t);
00348 netsnmp_transport_free(t);
00349 return NULL;
00350 }
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 #ifdef WIN32
00361 opt = 1;
00362 ioctlsocket(t->sock, FIONBIO, &opt);
00363 #else
00364 sockflags = fcntl(t->sock, F_GETFL, 0);
00365 fcntl(t->sock, F_SETFL, sockflags | O_NONBLOCK);
00366 #endif
00367
00368
00369
00370
00371
00372 rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN);
00373 if (rc != 0) {
00374 netsnmp_tcp6_close(t);
00375 netsnmp_transport_free(t);
00376 return NULL;
00377 }
00378
00379
00380
00381
00382
00383 } else {
00384 t->remote = (unsigned char*)malloc(18);
00385 if (t->remote == NULL) {
00386 netsnmp_tcp6_close(t);
00387 netsnmp_transport_free(t);
00388 return NULL;
00389 }
00390 memcpy(t->remote, addr->sin6_addr.s6_addr, 16);
00391 t->remote[16] = (addr->sin6_port & 0xff00) >> 8;
00392 t->remote[17] = (addr->sin6_port & 0x00ff) >> 0;
00393 t->remote_length = 18;
00394
00395
00396
00397
00398
00399
00400
00401
00402 rc = connect(t->sock, (struct sockaddr *) addr,
00403 sizeof(struct sockaddr_in6));
00404
00405 DEBUGMSGTL(("netsnmp_tcp6", "connect returns %d\n", rc));
00406
00407 if (rc < 0) {
00408 netsnmp_tcp6_close(t);
00409 netsnmp_transport_free(t);
00410 return NULL;
00411 }
00412
00413
00414
00415
00416
00417
00418 netsnmp_sock_buffer_set(t->sock, SO_SNDBUF, local, 0);
00419 netsnmp_sock_buffer_set(t->sock, SO_RCVBUF, local, 0);
00420 }
00421
00422
00423
00424
00425
00426
00427 t->msgMaxSize = 0x7fffffff;
00428 t->f_recv = netsnmp_tcp6_recv;
00429 t->f_send = netsnmp_tcp6_send;
00430 t->f_close = netsnmp_tcp6_close;
00431 t->f_accept = netsnmp_tcp6_accept;
00432 t->f_fmtaddr = netsnmp_tcp6_fmtaddr;
00433
00434 return t;
00435 }
00436
00437
00438
00439
00440 extern int
00441 netsnmp_sockaddr_in6_2(struct sockaddr_in6*, const char*, const char*);
00442
00443 netsnmp_transport *
00444 netsnmp_tcp6_create_tstring(const char *str, int local,
00445 const char *default_target)
00446 {
00447 struct sockaddr_in6 addr;
00448
00449 if (netsnmp_sockaddr_in6_2(&addr, str, default_target)) {
00450 return netsnmp_tcp6_transport(&addr, local);
00451 } else {
00452 return NULL;
00453 }
00454 }
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466 netsnmp_transport *
00467 netsnmp_tcp6_create_ostring(const u_char * o, size_t o_len, int local)
00468 {
00469 struct sockaddr_in6 addr;
00470
00471 if (o_len == 18) {
00472 memset((u_char *) & addr, 0, sizeof(struct sockaddr_in6));
00473 addr.sin6_family = AF_INET6;
00474 memcpy((u_char *) & (addr.sin6_addr.s6_addr), o, 16);
00475 addr.sin6_port = (o[16] << 8) + o[17];
00476 return netsnmp_tcp6_transport(&addr, local);
00477 }
00478 return NULL;
00479 }
00480
00481
00482 void
00483 netsnmp_tcp6_ctor(void)
00484 {
00485 tcp6Domain.name = netsnmp_TCPIPv6Domain;
00486 tcp6Domain.name_length = sizeof(netsnmp_TCPIPv6Domain) / sizeof(oid);
00487 tcp6Domain.f_create_from_tstring_new = netsnmp_tcp6_create_tstring;
00488 tcp6Domain.f_create_from_ostring = netsnmp_tcp6_create_ostring;
00489 tcp6Domain.prefix = (const char**)calloc(4, sizeof(char *));
00490 tcp6Domain.prefix[0] = "tcp6";
00491 tcp6Domain.prefix[1] = "tcpv6";
00492 tcp6Domain.prefix[2] = "tcpipv6";
00493
00494 netsnmp_tdomain_register(&tcp6Domain);
00495 }
00496
00497 #endif
00498