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