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