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