00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <net-snmp/net-snmp-config.h>
00013
00014 #include <stdio.h>
00015 #include <sys/types.h>
00016 #include <ctype.h>
00017 #include <errno.h>
00018
00019 #if HAVE_STRING_H
00020 #include <string.h>
00021 #else
00022 #include <strings.h>
00023 #endif
00024 #if HAVE_STDLIB_H
00025 #include <stdlib.h>
00026 #endif
00027 #if HAVE_UNISTD_H
00028 #include <unistd.h>
00029 #endif
00030 #if HAVE_SYS_SOCKET_H
00031 #include <sys/socket.h>
00032 #endif
00033 #if HAVE_NETINET_IN_H
00034 #include <netinet/in.h>
00035 #endif
00036 #if HAVE_ARPA_INET_H
00037 #include <arpa/inet.h>
00038 #endif
00039 #if HAVE_NETDB_H
00040 #include <netdb.h>
00041 #endif
00042 #if HAVE_SYS_UIO_H
00043 #include <sys/uio.h>
00044 #endif
00045
00046 #if HAVE_WINSOCK_H
00047 #include <winsock2.h>
00048 #include <ws2tcpip.h>
00049 #endif
00050
00051 #if HAVE_DMALLOC_H
00052 #include <dmalloc.h>
00053 #endif
00054
00055 #include <net-snmp/types.h>
00056 #include <net-snmp/output_api.h>
00057 #include <net-snmp/config_api.h>
00058
00059 #include <net-snmp/library/snmp_transport.h>
00060 #include <net-snmp/library/snmpUDPDomain.h>
00061 #include <net-snmp/library/system.h>
00062 #include <net-snmp/library/tools.h>
00063
00064 #ifndef INADDR_NONE
00065 #define INADDR_NONE -1
00066 #endif
00067
00068 #ifdef MSG_DONTWAIT
00069 #define NETSNMP_DONTWAIT MSG_DONTWAIT
00070 #else
00071 #define NETSNMP_DONTWAIT 0
00072 #endif
00073
00074 static netsnmp_tdomain udpDomain;
00075
00076 typedef struct netsnmp_udp_addr_pair_s {
00077 struct sockaddr_in remote_addr;
00078 struct in_addr local_addr;
00079 } netsnmp_udp_addr_pair;
00080
00081
00082
00083
00084
00085 void _netsnmp_udp_sockopt_set(int fd, int server);
00086 int
00087 netsnmp_sockaddr_in2(struct sockaddr_in *addr,
00088 const char *inpeername, const char *default_target);
00089
00090
00091
00092
00093
00094
00095 char *
00096 netsnmp_udp_fmtaddr(netsnmp_transport *t, void *data, int len)
00097 {
00098 netsnmp_udp_addr_pair *addr_pair = NULL;
00099 struct hostent *host;
00100
00101 if (data != NULL && len == sizeof(netsnmp_udp_addr_pair)) {
00102 addr_pair = (netsnmp_udp_addr_pair *) data;
00103 } else if (t != NULL && t->data != NULL) {
00104 addr_pair = (netsnmp_udp_addr_pair *) t->data;
00105 }
00106
00107 if (addr_pair == NULL) {
00108 return strdup("UDP: unknown");
00109 } else {
00110 struct sockaddr_in *to = NULL;
00111 char tmp[64];
00112 to = (struct sockaddr_in *) &(addr_pair->remote_addr);
00113 if (to == NULL) {
00114 sprintf(tmp, "UDP: unknown->[%s]",
00115 inet_ntoa(addr_pair->local_addr));
00116 } else if ( t && t->flags & NETSNMP_TRANSPORT_FLAG_HOSTNAME ) {
00117 host = gethostbyaddr((char *)&to->sin_addr, 4, AF_INET);
00118 return (host ? strdup(host->h_name) : NULL);
00119 } else {
00120 sprintf(tmp, "UDP: [%s]:%hu->",
00121 inet_ntoa(to->sin_addr), ntohs(to->sin_port));
00122 sprintf(tmp + strlen(tmp), "[%s]", inet_ntoa(addr_pair->local_addr));
00123 }
00124 return strdup(tmp);
00125 }
00126 }
00127
00128
00129
00130 #if defined(linux) && defined(IP_PKTINFO)
00131
00132 # define netsnmp_dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))
00133
00134 int netsnmp_udp_recvfrom(int s, void *buf, int len, struct sockaddr *from, socklen_t *fromlen, struct in_addr *dstip)
00135 {
00136 int r;
00137 struct iovec iov[1];
00138 char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
00139 struct cmsghdr *cmsgptr;
00140 struct msghdr msg;
00141
00142 iov[0].iov_base = buf;
00143 iov[0].iov_len = len;
00144
00145 memset(&msg, 0, sizeof msg);
00146 msg.msg_name = from;
00147 msg.msg_namelen = *fromlen;
00148 msg.msg_iov = iov;
00149 msg.msg_iovlen = 1;
00150 msg.msg_control = &cmsg;
00151 msg.msg_controllen = sizeof(cmsg);
00152
00153 r = recvmsg(s, &msg, NETSNMP_DONTWAIT);
00154
00155 if (r == -1) {
00156 return -1;
00157 }
00158
00159 DEBUGMSGTL(("netsnmp_udp", "got source addr: %s\n", inet_ntoa(((struct sockaddr_in *)from)->sin_addr)));
00160 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
00161 if (cmsgptr->cmsg_level == SOL_IP && cmsgptr->cmsg_type == IP_PKTINFO) {
00162 memcpy((void *) dstip, netsnmp_dstaddr(cmsgptr), sizeof(struct in_addr));
00163 DEBUGMSGTL(("netsnmp_udp", "got destination (local) addr %s\n",
00164 inet_ntoa(*dstip)));
00165 }
00166 }
00167 return r;
00168 }
00169
00170 int netsnmp_udp_sendto(int fd, struct in_addr *srcip, struct sockaddr *remote,
00171 void *data, int len)
00172 {
00173 struct iovec iov = { data, len };
00174 struct {
00175 struct cmsghdr cm;
00176 struct in_pktinfo ipi;
00177 } cmsg;
00178 struct msghdr m;
00179
00180 memset(&cmsg, 0, sizeof(cmsg));
00181 cmsg.cm.cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
00182 cmsg.cm.cmsg_level = SOL_IP;
00183 cmsg.cm.cmsg_type = IP_PKTINFO;
00184 cmsg.ipi.ipi_ifindex = 0;
00185 cmsg.ipi.ipi_spec_dst.s_addr = (srcip ? srcip->s_addr : INADDR_ANY);
00186
00187 m.msg_name = remote;
00188 m.msg_namelen = sizeof(struct sockaddr_in);
00189 m.msg_iov = &iov;
00190 m.msg_iovlen = 1;
00191 m.msg_control = &cmsg;
00192 m.msg_controllen = sizeof(cmsg);
00193 m.msg_flags = 0;
00194
00195 return sendmsg(fd, &m, MSG_NOSIGNAL|MSG_DONTWAIT);
00196 }
00197 #endif
00198
00199
00200
00201
00202
00203
00204
00205 static int
00206 netsnmp_udp_recv(netsnmp_transport *t, void *buf, int size,
00207 void **opaque, int *olength)
00208 {
00209 int rc = -1;
00210 socklen_t fromlen = sizeof(struct sockaddr);
00211 netsnmp_udp_addr_pair *addr_pair = NULL;
00212 struct sockaddr *from;
00213
00214 if (t != NULL && t->sock >= 0) {
00215 addr_pair = (netsnmp_udp_addr_pair *) malloc(sizeof(netsnmp_udp_addr_pair));
00216 if (addr_pair == NULL) {
00217 *opaque = NULL;
00218 *olength = 0;
00219 return -1;
00220 } else {
00221 memset(addr_pair, 0, sizeof(netsnmp_udp_addr_pair));
00222 from = (struct sockaddr *) &(addr_pair->remote_addr);
00223 }
00224
00225 while (rc < 0) {
00226 #if defined(linux) && defined(IP_PKTINFO)
00227 rc = netsnmp_udp_recvfrom(t->sock, buf, size, from, &fromlen, &(addr_pair->local_addr));
00228 #else
00229 rc = recvfrom(t->sock, buf, size, NETSNMP_DONTWAIT, from, &fromlen);
00230 #endif
00231 if (rc < 0 && errno != EINTR) {
00232 break;
00233 }
00234 }
00235
00236 if (rc >= 0) {
00237 char *str = netsnmp_udp_fmtaddr(NULL, addr_pair, sizeof(netsnmp_udp_addr_pair));
00238 DEBUGMSGTL(("netsnmp_udp",
00239 "recvfrom fd %d got %d bytes (from %s)\n",
00240 t->sock, rc, str));
00241 free(str);
00242 } else {
00243 DEBUGMSGTL(("netsnmp_udp", "recvfrom fd %d err %d (\"%s\")\n",
00244 t->sock, errno, strerror(errno)));
00245 }
00246 *opaque = (void *)addr_pair;
00247 *olength = sizeof(netsnmp_udp_addr_pair);
00248 }
00249 return rc;
00250 }
00251
00252
00253
00254 static int
00255 netsnmp_udp_send(netsnmp_transport *t, void *buf, int size,
00256 void **opaque, int *olength)
00257 {
00258 int rc = -1;
00259 netsnmp_udp_addr_pair *addr_pair = NULL;
00260 struct sockaddr *to = NULL;
00261
00262 if (opaque != NULL && *opaque != NULL &&
00263 *olength == sizeof(netsnmp_udp_addr_pair)) {
00264 addr_pair = (netsnmp_udp_addr_pair *) (*opaque);
00265 } else if (t != NULL && t->data != NULL &&
00266 t->data_length == sizeof(netsnmp_udp_addr_pair)) {
00267 addr_pair = (netsnmp_udp_addr_pair *) (t->data);
00268 }
00269
00270 to = (struct sockaddr *) &(addr_pair->remote_addr);
00271
00272 if (to != NULL && t != NULL && t->sock >= 0) {
00273 char *str = netsnmp_udp_fmtaddr(NULL, (void *) addr_pair,
00274 sizeof(netsnmp_udp_addr_pair));
00275 DEBUGMSGTL(("netsnmp_udp", "send %d bytes from %p to %s on fd %d\n",
00276 size, buf, str, t->sock));
00277 free(str);
00278 while (rc < 0) {
00279 #if defined(linux) && defined(IP_PKTINFO)
00280 rc = netsnmp_udp_sendto(t->sock, addr_pair ? &(addr_pair->local_addr) : NULL, to, buf, size);
00281 #else
00282 rc = sendto(t->sock, buf, size, 0, to, sizeof(struct sockaddr));
00283 #endif
00284 if (rc < 0 && errno != EINTR) {
00285 DEBUGMSGTL(("netsnmp_udp", "sendto error, rc %d (errno %d)\n",
00286 rc, errno));
00287 break;
00288 }
00289 }
00290 }
00291 return rc;
00292 }
00293
00294
00295
00296 static int
00297 netsnmp_udp_close(netsnmp_transport *t)
00298 {
00299 int rc = -1;
00300 if (t->sock >= 0) {
00301 #ifndef HAVE_CLOSESOCKET
00302 rc = close(t->sock);
00303 #else
00304 rc = closesocket(t->sock);
00305 #endif
00306 t->sock = -1;
00307 }
00308 return rc;
00309 }
00310
00311
00312
00313
00314
00315
00316
00317
00318 static int
00319 _sock_buffer_maximize(int s, int optname, const char *buftype, int size)
00320 {
00321 int curbuf = 0;
00322 socklen_t curbuflen = sizeof(int);
00323 int lo, mid, hi;
00324
00325
00326
00327
00328 if ((getsockopt(s, SOL_SOCKET, optname, (void *) &curbuf,
00329 &curbuflen) == 0)
00330 && (curbuflen == sizeof(int))) {
00331
00332 DEBUGMSGTL(("verbose:socket:buffer:max", "Current %s is %d\n",
00333 buftype, curbuf));
00334
00335
00336
00337
00338
00339 if (size <= curbuf) {
00340 DEBUGMSGTL(("verbose:socket:buffer:max",
00341 "Requested %s <= current buffer\n", buftype));
00342 return curbuf;
00343 }
00344
00345
00346
00347
00348
00349 hi = size;
00350 lo = curbuf;
00351
00352 while (hi - lo > 1024) {
00353 mid = (lo + hi) / 2;
00354 if (setsockopt(s, SOL_SOCKET, optname, (void *) &mid,
00355 sizeof(int)) == 0) {
00356 lo = mid;
00357 } else {
00358 hi = mid;
00359 }
00360 }
00361
00362
00363
00364
00365 if (getsockopt(s,SOL_SOCKET, optname, (void *) &curbuf,
00366 &curbuflen) == 0) {
00367 DEBUGMSGTL(("socket:buffer:max",
00368 "Maximized %s: %d\n",buftype, curbuf));
00369 }
00370 } else {
00371
00372
00373
00374
00375
00376 DEBUGMSGTL(("socket:buffer:max", "Get %s failed ... giving up!\n",
00377 buftype));
00378 curbuf = -1;
00379 }
00380
00381 return curbuf;
00382 }
00383
00384
00385 static const char *
00386 _sock_buf_type_get(int optname, int local)
00387 {
00388 if (optname == SO_SNDBUF) {
00389 if (local)
00390 return "server send buffer";
00391 else
00392 return "client send buffer";
00393 } else if (optname == SO_RCVBUF) {
00394 if (local)
00395 return "server receive buffer";
00396 else
00397 return "client receive buffer";
00398 }
00399
00400 return "unknown buffer";
00401 }
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412 static int
00413 _sock_buffer_size_get(int optname, int local, const char **buftype)
00414 {
00415 int size;
00416
00417 if (NULL != buftype)
00418 *buftype = _sock_buf_type_get(optname, local);
00419
00420 if (optname == SO_SNDBUF) {
00421 if (local) {
00422 size = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
00423 NETSNMP_DS_LIB_SERVERSENDBUF);
00424 #ifdef NETSNMP_DEFAULT_SERVER_SEND_BUF
00425 if (size <= 0)
00426 size = NETSNMP_DEFAULT_SERVER_SEND_BUF;
00427 #endif
00428 } else {
00429 size = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
00430 NETSNMP_DS_LIB_CLIENTSENDBUF);
00431 #ifdef NETSNMP_DEFAULT_CLIENT_SEND_BUF
00432 if (size <= 0)
00433 size = NETSNMP_DEFAULT_CLIENT_SEND_BUF;
00434 #endif
00435 }
00436 } else if (optname == SO_RCVBUF) {
00437 if (local) {
00438 size = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
00439 NETSNMP_DS_LIB_SERVERRECVBUF);
00440 #ifdef NETSNMP_DEFAULT_SERVER_RECV_BUF
00441 if (size <= 0)
00442 size = NETSNMP_DEFAULT_SERVER_RECV_BUF;
00443 #endif
00444 } else {
00445 size = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
00446 NETSNMP_DS_LIB_CLIENTRECVBUF);
00447 #ifdef NETSNMP_DEFAULT_CLIENT_RECV_BUF
00448 if (size <= 0)
00449 size = NETSNMP_DEFAULT_CLIENT_RECV_BUF;
00450 #endif
00451 }
00452 } else {
00453 size = 0;
00454 }
00455
00456 DEBUGMSGTL(("socket:buffer", "Requested %s is %d\n",
00457 (buftype) ? *buftype : "unknown buffer", size));
00458
00459 return(size);
00460 }
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473 int
00474 netsnmp_sock_buffer_set(int s, int optname, int local, int size)
00475 {
00476 #if ! defined(SO_SNDBUF) && ! defined(SO_RCVBUF)
00477 DEBUGMSGTL(("socket:buffer", "Changing socket buffer is not supported\n"));
00478 return -1;
00479 #else
00480 const char *buftype;
00481 int curbuf = 0;
00482 socklen_t curbuflen = sizeof(int);
00483
00484 # ifndef SO_SNDBUF
00485 if (SO_SNDBUF == optname) {
00486 DEBUGMSGTL(("socket:buffer",
00487 "Changing socket send buffer is not supported\n"));
00488 return -1;
00489 }
00490 # endif
00491 # ifndef SO_RCVBUF
00492 if (SO_RCVBUF == optname) {
00493 DEBUGMSGTL(("socket:buffer",
00494 "Changing socket receive buffer is not supported\n"));
00495 return -1;
00496 }
00497 # endif
00498
00499
00500
00501
00502 if (0 == size)
00503 size = _sock_buffer_size_get(optname, local, &buftype);
00504 else {
00505 buftype = _sock_buf_type_get(optname, local);
00506 DEBUGMSGT(("verbose:socket:buffer", "Requested %s is %d\n",
00507 buftype, size));
00508 }
00509
00510 if ((getsockopt(s, SOL_SOCKET, optname, (void *) &curbuf,
00511 &curbuflen) == 0)
00512 && (curbuflen == sizeof(int))) {
00513
00514 DEBUGMSGT(("verbose:socket:buffer", "Original %s is %d\n",
00515 buftype, curbuf));
00516 if (curbuf >= size) {
00517 DEBUGMSGT(("verbose:socket:buffer",
00518 "New %s size is smaller than original!\n", buftype));
00519 }
00520 }
00521
00522
00523
00524
00525
00526 if (size <= 0) {
00527 DEBUGMSGT(("socket:buffer",
00528 "%s not valid or not specified; using OS default(%d)\n",
00529 buftype,curbuf));
00530 return curbuf;
00531 }
00532
00533
00534
00535
00536 if (setsockopt(s, SOL_SOCKET, optname, (void *) &size, sizeof(int)) == 0) {
00537
00538
00539
00540
00541
00542 DEBUGIF("socket:buffer") {
00543 DEBUGMSGT(("socket:buffer", "Set %s to %d\n",
00544 buftype, size));
00545 if ((getsockopt(s, SOL_SOCKET, optname, (void *) &curbuf,
00546 &curbuflen) == 0)
00547 && (curbuflen == sizeof(int))) {
00548
00549 DEBUGMSGT(("verbose:socket:buffer",
00550 "Now %s is %d\n", buftype, curbuf));
00551 }
00552 }
00553
00554
00555
00556
00557
00558
00559
00560 if (curbuf < size) {
00561 curbuf = _sock_buffer_maximize(s, optname, buftype, size);
00562 if(-1 != curbuf)
00563 size = curbuf;
00564 }
00565
00566 } else {
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 DEBUGMSGTL(("socket:buffer", "couldn't set %s to %d\n",
00578 buftype, size));
00579
00580 curbuf = _sock_buffer_maximize(s, optname, buftype, size);
00581 if(-1 != curbuf)
00582 size = curbuf;
00583 }
00584
00585 return size;
00586 #endif
00587 }
00588
00589
00590
00591
00592
00593
00594
00595 netsnmp_transport *
00596 netsnmp_udp_transport(struct sockaddr_in *addr, int local)
00597 {
00598 netsnmp_transport *t = NULL;
00599 int rc = 0;
00600 char *str = NULL;
00601 char *client_socket = NULL;
00602 netsnmp_udp_addr_pair addr_pair;
00603
00604 if (addr == NULL || addr->sin_family != AF_INET) {
00605 return NULL;
00606 }
00607
00608 memset(&addr_pair, 0, sizeof(netsnmp_udp_addr_pair));
00609 memcpy(&(addr_pair.remote_addr), addr, sizeof(struct sockaddr_in));
00610
00611 t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
00612 if (t == NULL) {
00613 return NULL;
00614 }
00615
00616 str = netsnmp_udp_fmtaddr(NULL, (void *)&addr_pair,
00617 sizeof(netsnmp_udp_addr_pair));
00618 DEBUGMSGTL(("netsnmp_udp", "open %s %s\n", local ? "local" : "remote",
00619 str));
00620 free(str);
00621
00622 memset(t, 0, sizeof(netsnmp_transport));
00623
00624 t->domain = netsnmpUDPDomain;
00625 t->domain_length = netsnmpUDPDomain_len;
00626
00627 t->sock = socket(PF_INET, SOCK_DGRAM, 0);
00628 if (t->sock < 0) {
00629 netsnmp_transport_free(t);
00630 return NULL;
00631 }
00632
00633 _netsnmp_udp_sockopt_set(t->sock, local);
00634
00635 if (local) {
00636
00637
00638
00639
00640
00641
00642 t->local = (u_char *) malloc(6);
00643 if (t->local == NULL) {
00644 netsnmp_transport_free(t);
00645 return NULL;
00646 }
00647 memcpy(t->local, (u_char *) & (addr->sin_addr.s_addr), 4);
00648 t->local[4] = (htons(addr->sin_port) & 0xff00) >> 8;
00649 t->local[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
00650 t->local_length = 6;
00651
00652 #if defined(linux) && defined(IP_PKTINFO)
00653 {
00654 int sockopt = 1;
00655 if (setsockopt(t->sock, SOL_IP, IP_PKTINFO, &sockopt, sizeof sockopt) == -1) {
00656 DEBUGMSGTL(("netsnmp_udp", "couldn't set IP_PKTINFO: %s\n",
00657 strerror(errno)));
00658 netsnmp_transport_free(t);
00659 return NULL;
00660 }
00661 DEBUGMSGTL(("netsnmp_udp", "set IP_PKTINFO\n"));
00662 }
00663 #endif
00664 rc = bind(t->sock, (struct sockaddr *) addr,
00665 sizeof(struct sockaddr));
00666 if (rc != 0) {
00667 netsnmp_udp_close(t);
00668 netsnmp_transport_free(t);
00669 return NULL;
00670 }
00671 t->data = NULL;
00672 t->data_length = 0;
00673 } else {
00674
00675
00676
00677
00678
00679 client_socket = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
00680 NETSNMP_DS_LIB_CLIENT_ADDR);
00681 if (client_socket) {
00682 struct sockaddr_in client_addr;
00683 netsnmp_sockaddr_in2(&client_addr, client_socket, NULL);
00684 addr_pair.local_addr = client_addr.sin_addr;
00685 rc = bind(t->sock, (struct sockaddr *)&client_addr,
00686 sizeof(struct sockaddr));
00687 if ( rc != 0 ) {
00688 DEBUGMSGTL(("netsnmp_udp", "failed to bind for clientaddr: %d %s\n",
00689 errno, strerror(errno)));
00690 netsnmp_udp_close(t);
00691 netsnmp_transport_free(t);
00692 return NULL;
00693 }
00694 }
00695
00696 str = netsnmp_udp_fmtaddr(NULL, (void *)&addr_pair,
00697 sizeof(netsnmp_udp_addr_pair));
00698 DEBUGMSGTL(("netsnmp_udp", "client open %s\n", str));
00699 free(str);
00700
00701
00702
00703
00704
00705
00706 t->data = malloc(sizeof(netsnmp_udp_addr_pair));
00707 t->remote = (u_char *)malloc(6);
00708 if (t->data == NULL || t->remote == NULL) {
00709 netsnmp_transport_free(t);
00710 return NULL;
00711 }
00712 memcpy(t->remote, (u_char *) & (addr->sin_addr.s_addr), 4);
00713 t->remote[4] = (htons(addr->sin_port) & 0xff00) >> 8;
00714 t->remote[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
00715 t->remote_length = 6;
00716 memcpy(t->data, &addr_pair, sizeof(netsnmp_udp_addr_pair));
00717 t->data_length = sizeof(netsnmp_udp_addr_pair);
00718 }
00719
00720
00721
00722
00723
00724 t->msgMaxSize = 0xffff - 8 - 20;
00725 t->f_recv = netsnmp_udp_recv;
00726 t->f_send = netsnmp_udp_send;
00727 t->f_close = netsnmp_udp_close;
00728 t->f_accept = NULL;
00729 t->f_fmtaddr = netsnmp_udp_fmtaddr;
00730
00731 return t;
00732 }
00733
00734
00735 void
00736 _netsnmp_udp_sockopt_set(int fd, int local)
00737 {
00738 #ifdef SO_BSDCOMPAT
00739
00740
00741
00742
00743
00744 if (0 == netsnmp_os_prematch("Linux","2.4"))
00745 {
00746 int one = 1;
00747 DEBUGMSGTL(("socket:option", "setting socket option SO_BSDCOMPAT\n"));
00748 setsockopt(fd, SOL_SOCKET, SO_BSDCOMPAT, (void *) &one,
00749 sizeof(one));
00750 }
00751 #endif
00752
00753
00754
00755
00756
00757
00758 #ifdef ALLOW_PORT_HIJACKING
00759 #ifdef SO_REUSEADDR
00760
00761
00762
00763
00764 {
00765 int one = 1;
00766 DEBUGMSGTL(("socket:option", "setting socket option SO_REUSEADDR\n"));
00767 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &one,
00768 sizeof(one));
00769 }
00770 #endif
00771 #endif
00772
00773
00774
00775
00776
00777
00778
00779 netsnmp_sock_buffer_set(fd, SO_SNDBUF, local, 0);
00780 netsnmp_sock_buffer_set(fd, SO_RCVBUF, local, 0);
00781 }
00782
00783 int
00784 netsnmp_sockaddr_in2(struct sockaddr_in *addr,
00785 const char *inpeername, const char *default_target)
00786 {
00787 int ret;
00788
00789 if (addr == NULL) {
00790 return 0;
00791 }
00792
00793 DEBUGMSGTL(("netsnmp_sockaddr_in",
00794 "addr %p, inpeername \"%s\", default_target \"%s\"\n",
00795 addr, inpeername ? inpeername : "[NIL]",
00796 default_target ? default_target : "[NIL]"));
00797
00798 memset(addr, 0, sizeof(struct sockaddr_in));
00799 addr->sin_addr.s_addr = htonl(INADDR_ANY);
00800 addr->sin_family = AF_INET;
00801 addr->sin_port = htons((u_short)SNMP_PORT);
00802
00803 {
00804 int port = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
00805 NETSNMP_DS_LIB_DEFAULT_PORT);
00806
00807 if (port != 0) {
00808 addr->sin_port = htons((u_short)port);
00809 } else if (default_target != NULL)
00810 netsnmp_sockaddr_in2(addr, default_target, NULL);
00811 }
00812
00813 if (inpeername != NULL && *inpeername != '\0') {
00814 const char *host, *port;
00815 char *peername = NULL;
00816 char *cp;
00817
00818
00819
00820
00821
00822 peername = strdup(inpeername);
00823 if (peername == NULL) {
00824 return 0;
00825 }
00826
00827
00828
00829
00830 cp = strchr(peername, ':');
00831 if (cp != NULL) {
00832 *cp = '\0';
00833 port = cp + 1;
00834 host = peername;
00835 } else {
00836 host = NULL;
00837 port = peername;
00838 }
00839
00840
00841
00842
00843 if (port && *port == '\0')
00844 port = NULL;
00845
00846 if (port != NULL) {
00847 long int l;
00848 char* ep;
00849
00850 DEBUGMSGTL(("netsnmp_sockaddr_in", "check user service %s\n",
00851 port));
00852
00853 l = strtol(port, &ep, 10);
00854 if (ep != port && *ep == '\0' && 0 <= l && l <= 0x0ffff)
00855 addr->sin_port = htons((u_short)l);
00856 else {
00857 if (host == NULL) {
00858 DEBUGMSGTL(("netsnmp_sockaddr_in",
00859 "servname not numeric, "
00860 "check if it really is a destination)\n"));
00861 host = port;
00862 port = NULL;
00863 } else {
00864 DEBUGMSGTL(("netsnmp_sockaddr_in",
00865 "servname not numeric\n"));
00866 free(peername);
00867 return 0;
00868 }
00869 }
00870 }
00871
00872
00873
00874
00875 if (host && *host == '\0')
00876 host = NULL;
00877
00878 if (host != NULL) {
00879 DEBUGMSGTL(("netsnmp_sockaddr_in",
00880 "check destination %s\n", host));
00881
00882
00883 if (strcmp(peername, "255.255.255.255") == 0 ) {
00884
00885
00886
00887 DEBUGMSGTL(("netsnmp_sockaddr_in", "Explicit UDP broadcast\n"));
00888 addr->sin_addr.s_addr = INADDR_NONE;
00889 } else {
00890 ret =
00891 netsnmp_gethostbyname_v4(peername, &addr->sin_addr.s_addr);
00892 if (ret < 0) {
00893 DEBUGMSGTL(("netsnmp_sockaddr_in",
00894 "couldn't resolve hostname\n"));
00895 free(peername);
00896 return 0;
00897 }
00898 DEBUGMSGTL(("netsnmp_sockaddr_in",
00899 "hostname (resolved okay)\n"));
00900 }
00901 }
00902 free(peername);
00903 }
00904
00905
00906
00907
00908
00909 DEBUGMSGTL(("netsnmp_sockaddr_in", "return { AF_INET, %s:%hu }\n",
00910 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port)));
00911 return 1;
00912 }
00913
00914
00915 int
00916 netsnmp_sockaddr_in(struct sockaddr_in *addr,
00917 const char *inpeername, int remote_port)
00918 {
00919 char buf[sizeof(int) * 3 + 2];
00920 sprintf(buf, ":%u", remote_port);
00921 return netsnmp_sockaddr_in2(addr, inpeername, remote_port ? buf : NULL);
00922 }
00923
00924 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
00925
00926
00927
00928
00929
00930 #define EXAMPLE_NETWORK "NETWORK"
00931 #define EXAMPLE_COMMUNITY "COMMUNITY"
00932
00933 typedef struct _com2SecEntry {
00934 char community[COMMUNITY_MAX_LEN];
00935 unsigned long network;
00936 unsigned long mask;
00937 char secName[VACMSTRINGLEN];
00938 char contextName[VACMSTRINGLEN];
00939 struct _com2SecEntry *next;
00940 } com2SecEntry;
00941
00942 com2SecEntry *com2SecList = NULL, *com2SecListLast = NULL;
00943
00944 void
00945 netsnmp_udp_parse_security(const char *token, char *param)
00946 {
00947 char secName[VACMSTRINGLEN];
00948 char contextName[VACMSTRINGLEN];
00949 char community[COMMUNITY_MAX_LEN];
00950 char source[SNMP_MAXBUF_SMALL];
00951 char *cp = NULL;
00952 const char *strmask = NULL;
00953 com2SecEntry *e = NULL;
00954 in_addr_t network = 0, mask = 0;
00955
00956
00957
00958
00959
00960 cp = copy_nword( param, secName, sizeof(secName));
00961 if (strcmp(secName, "-Cn") == 0) {
00962 if (!cp) {
00963 config_perror("missing CONTEXT_NAME parameter");
00964 return;
00965 }
00966 cp = copy_nword( cp, contextName, sizeof(contextName));
00967 cp = copy_nword( cp, secName, sizeof(secName));
00968 } else {
00969 contextName[0] = '\0';
00970 }
00971 if (secName[0] == '\0') {
00972 config_perror("missing NAME parameter");
00973 return;
00974 } else if (strlen(secName) > (VACMSTRINGLEN - 1)) {
00975 config_perror("security name too long");
00976 return;
00977 }
00978 cp = copy_nword( cp, source, sizeof(source));
00979 if (source[0] == '\0') {
00980 config_perror("missing SOURCE parameter");
00981 return;
00982 } else if (strncmp(source, EXAMPLE_NETWORK, strlen(EXAMPLE_NETWORK)) ==
00983 0) {
00984 config_perror("example config NETWORK not properly configured");
00985 return;
00986 }
00987 cp = copy_nword( cp, community, sizeof(community));
00988 if (community[0] == '\0') {
00989 config_perror("missing COMMUNITY parameter\n");
00990 return;
00991 } else
00992 if (strncmp
00993 (community, EXAMPLE_COMMUNITY, strlen(EXAMPLE_COMMUNITY))
00994 == 0) {
00995 config_perror("example config COMMUNITY not properly configured");
00996 return;
00997 } else if (strlen(community) > (COMMUNITY_MAX_LEN - 1)) {
00998 config_perror("community name too long");
00999 return;
01000 }
01001
01002
01003
01004
01005
01006 cp = strchr(source, '/');
01007 if (cp != NULL) {
01008
01009
01010
01011 *cp = '\0';
01012 strmask = cp + 1;
01013 }
01014
01015
01016
01017
01018
01019 if ((strcmp(source, "default") == 0)
01020 || (strcmp(source, "0.0.0.0") == 0)) {
01021 network = 0;
01022 strmask = "0.0.0.0";
01023 } else {
01024
01025
01026
01027 network = inet_addr(source);
01028
01029 if (network == (in_addr_t) -1) {
01030
01031
01032
01033 int ret = netsnmp_gethostbyname_v4(source, &network);
01034 if (ret < 0) {
01035 config_perror("cannot resolve source hostname");
01036 return;
01037 }
01038 }
01039 }
01040
01041
01042
01043
01044
01045 if (strmask == NULL || *strmask == '\0') {
01046
01047
01048
01049 mask = 0xffffffffL;
01050 } else {
01051 if (strchr(strmask, '.')) {
01052
01053
01054
01055 mask = inet_addr(strmask);
01056 if (mask == (in_addr_t) -1 &&
01057 strncmp(strmask, "255.255.255.255", 15) != 0) {
01058 config_perror("bad mask");
01059 return;
01060 }
01061 } else {
01062
01063
01064
01065 int maskLen = atoi(strmask), maskBit = 0x80000000L;
01066 if (maskLen <= 0 || maskLen > 32) {
01067 config_perror("bad mask length");
01068 return;
01069 }
01070 while (maskLen--) {
01071 mask |= maskBit;
01072 maskBit >>= 1;
01073 }
01074 mask = htonl(mask);
01075 }
01076 }
01077
01078
01079
01080
01081
01082 if (network & ~mask) {
01083 config_perror("source/mask mismatch");
01084 return;
01085 }
01086
01087 e = (com2SecEntry *) malloc(sizeof(com2SecEntry));
01088 if (e == NULL) {
01089 config_perror("memory error");
01090 return;
01091 }
01092
01093
01094
01095
01096
01097
01098 DEBUGMSGTL(("netsnmp_udp_parse_security",
01099 "<\"%s\", 0x%08x/0x%08x> => \"%s\"\n", community, network,
01100 mask, secName));
01101
01102 strcpy(e->contextName, contextName);
01103 strcpy(e->secName, secName);
01104 strcpy(e->community, community);
01105 e->network = network;
01106 e->mask = mask;
01107 e->next = NULL;
01108
01109 if (com2SecListLast != NULL) {
01110 com2SecListLast->next = e;
01111 com2SecListLast = e;
01112 } else {
01113 com2SecListLast = com2SecList = e;
01114 }
01115 }
01116
01117
01118 void
01119 netsnmp_udp_com2SecList_free(void)
01120 {
01121 com2SecEntry *e = com2SecList;
01122 while (e != NULL) {
01123 com2SecEntry *tmp = e;
01124 e = e->next;
01125 free(tmp);
01126 }
01127 com2SecList = com2SecListLast = NULL;
01128 }
01129 #endif
01130
01131 void
01132 netsnmp_udp_agent_config_tokens_register(void)
01133 {
01134 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
01135 register_app_config_handler("com2sec", netsnmp_udp_parse_security,
01136 netsnmp_udp_com2SecList_free,
01137 "[-Cn CONTEXT] secName IPv4-network-address[/netmask] community");
01138 #endif
01139 }
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
01151 int
01152 netsnmp_udp_getSecName(void *opaque, int olength,
01153 const char *community,
01154 size_t community_len, char **secName,
01155 char **contextName)
01156 {
01157 com2SecEntry *c;
01158 netsnmp_udp_addr_pair *addr_pair = (netsnmp_udp_addr_pair *) opaque;
01159 struct sockaddr_in *from = (struct sockaddr_in *) &(addr_pair->remote_addr);
01160 char *ztcommunity = NULL;
01161
01162 if (secName != NULL) {
01163 *secName = NULL;
01164 }
01165
01166
01167
01168
01169
01170
01171 if (com2SecList == NULL) {
01172 DEBUGMSGTL(("netsnmp_udp_getSecName", "no com2sec entries\n"));
01173 return 0;
01174 }
01175
01176
01177
01178
01179
01180
01181 DEBUGMSGTL(("netsnmp_udp_getSecName", "opaque = %p (len = %d), sizeof = %d, family = %d (%d)\n",
01182 opaque, olength, (int)sizeof(netsnmp_udp_addr_pair), from->sin_family, AF_INET));
01183 if (opaque == NULL || olength != sizeof(netsnmp_udp_addr_pair) ||
01184 from->sin_family != AF_INET) {
01185 DEBUGMSGTL(("netsnmp_udp_getSecName",
01186 "no IPv4 source address in PDU?\n"));
01187 return 1;
01188 }
01189
01190 DEBUGIF("netsnmp_udp_getSecName") {
01191 ztcommunity = (char *)malloc(community_len + 1);
01192 if (ztcommunity != NULL) {
01193 memcpy(ztcommunity, community, community_len);
01194 ztcommunity[community_len] = '\0';
01195 }
01196
01197 DEBUGMSGTL(("netsnmp_udp_getSecName", "resolve <\"%s\", 0x%08x>\n",
01198 ztcommunity ? ztcommunity : "<malloc error>",
01199 from->sin_addr.s_addr));
01200 }
01201
01202 for (c = com2SecList; c != NULL; c = c->next) {
01203 DEBUGMSGTL(("netsnmp_udp_getSecName","compare <\"%s\", 0x%08lx/0x%08lx>",
01204 c->community, c->network, c->mask));
01205 if ((community_len == strlen(c->community)) &&
01206 (memcmp(community, c->community, community_len) == 0) &&
01207 ((from->sin_addr.s_addr & c->mask) == c->network)) {
01208 DEBUGMSG(("netsnmp_udp_getSecName", "... SUCCESS\n"));
01209 if (secName != NULL) {
01210 *secName = c->secName;
01211 *contextName = c->contextName;
01212 }
01213 break;
01214 }
01215 DEBUGMSG(("netsnmp_udp_getSecName", "... nope\n"));
01216 }
01217 if (ztcommunity != NULL) {
01218 free(ztcommunity);
01219 }
01220 return 1;
01221 }
01222 #endif
01223
01224
01225 netsnmp_transport *
01226 netsnmp_udp_create_tstring(const char *str, int local,
01227 const char *default_target)
01228 {
01229 struct sockaddr_in addr;
01230
01231 if (netsnmp_sockaddr_in2(&addr, str, default_target)) {
01232 return netsnmp_udp_transport(&addr, local);
01233 } else {
01234 return NULL;
01235 }
01236 }
01237
01238
01239 netsnmp_transport *
01240 netsnmp_udp_create_ostring(const u_char * o, size_t o_len, int local)
01241 {
01242 struct sockaddr_in addr;
01243
01244 if (o_len == 6) {
01245 unsigned short porttmp = (o[4] << 8) + o[5];
01246 addr.sin_family = AF_INET;
01247 memcpy((u_char *) & (addr.sin_addr.s_addr), o, 4);
01248 addr.sin_port = htons(porttmp);
01249 return netsnmp_udp_transport(&addr, local);
01250 }
01251 return NULL;
01252 }
01253
01254
01255 void
01256 netsnmp_udp_ctor(void)
01257 {
01258 udpDomain.name = netsnmpUDPDomain;
01259 udpDomain.name_length = netsnmpUDPDomain_len;
01260 udpDomain.prefix = (const char**)calloc(2, sizeof(char *));
01261 udpDomain.prefix[0] = "udp";
01262
01263 udpDomain.f_create_from_tstring_new = netsnmp_udp_create_tstring;
01264 udpDomain.f_create_from_ostring = netsnmp_udp_create_ostring;
01265
01266 netsnmp_tdomain_register(&udpDomain);
01267 }