[Pkg-net-snmp-devel] [Patch] net-snmp 5.3.1-2: 24_pktinfo.patch
breaks TCP
Jan Andres
jandres at gmx.net
Fri Feb 9 22:15:06 CET 2007
Hi,
With 24_pktinfo.patch applied snmpd will never respond to TCP
requests, because the address -> security name mapping always fails.
I propose the patch attached as a replacement for 24_pktinfo.patch. It's
the version of the fix as diffed from the V5-3-patches branch of net-snmp,
and includes the fix for the TCP code.
Regards,
Jan
--
Jan Andres <jandres at gmx.net>
-------------- next part --------------
diff -ur net-snmp-5.3.1/snmplib/snmpTCPDomain.c net-snmp-5.3.1-fixed/snmplib/snmpTCPDomain.c
--- net-snmp-5.3.1/snmplib/snmpTCPDomain.c 2005-09-16 12:30:48.000000000 +0200
+++ net-snmp-5.3.1-fixed/snmplib/snmpTCPDomain.c 2007-02-09 20:52:29.112680146 +0100
@@ -44,6 +44,12 @@
#include <net-snmp/library/snmpUDPDomain.h>
#include <net-snmp/library/snmpTCPDomain.h>
+/* Copied from snmpUDPDomain.c */
+typedef struct netsnmp_udp_addr_pair_s {
+ struct sockaddr_in remote_addr;
+ struct in_addr local_addr;
+} netsnmp_udp_addr_pair;
+
oid netsnmp_snmpTCPDomain[] = { TRANSPORT_DOMAIN_TCP_IP };
static netsnmp_tdomain tcpDomain;
@@ -55,18 +61,23 @@
static char *
netsnmp_tcp_fmtaddr(netsnmp_transport *t, void *data, int len)
{
- struct sockaddr_in *to = NULL;
+ netsnmp_udp_addr_pair *addr_pair = NULL;
- if (data != NULL && len == sizeof(struct sockaddr_in)) {
- to = (struct sockaddr_in *) data;
- } else if (t != NULL && t->data != NULL &&
- t->data_length == sizeof(struct sockaddr_in)) {
- to = (struct sockaddr_in *) t->data;
+ if (data != NULL && len == sizeof(netsnmp_udp_addr_pair)) {
+ addr_pair = (netsnmp_udp_addr_pair *) data;
+ } else if (t != NULL && t->data != NULL) {
+ addr_pair = (netsnmp_udp_addr_pair *) t->data;
}
- if (to == NULL) {
+
+ if (addr_pair == NULL) {
return strdup("TCP: unknown");
} else {
- char tmp[64];
+ struct sockaddr_in *to = NULL;
+ char tmp[64];
+ to = (struct sockaddr_in *) &(addr_pair->remote_addr);
+ if (to == NULL) {
+ return strdup("TCP: unknown");
+ }
sprintf(tmp, "TCP: [%s]:%hd",
inet_ntoa(to->sin_addr), ntohs(to->sin_port));
@@ -163,19 +174,21 @@
netsnmp_tcp_accept(netsnmp_transport *t)
{
struct sockaddr *farend = NULL;
+ netsnmp_udp_addr_pair *addr_pair = NULL;
int newsock = -1, sockflags = 0;
socklen_t farendlen = sizeof(struct sockaddr_in);
char *str = NULL;
- farend = (struct sockaddr *) malloc(sizeof(struct sockaddr_in));
+ addr_pair = (netsnmp_udp_addr_pair *)malloc(sizeof(netsnmp_udp_addr_pair));
- if (farend == NULL) {
+ if (addr_pair == NULL) {
/*
* Indicate that the acceptance of this socket failed.
*/
DEBUGMSGTL(("netsnmp_tcp", "accept: malloc failed\n"));
return -1;
}
+ farend = (struct sockaddr_in *) &(addr_pair->remote_addr);
if (t != NULL && t->sock >= 0) {
newsock = accept(t->sock, farend, &farendlen);
@@ -191,8 +204,8 @@
free(t->data);
}
- t->data = farend;
- t->data_length = farendlen;
+ t->data = addr_pair;
+ t->data_length = sizeof(netsnmp_udp_addr_pair);
str = netsnmp_tcp_fmtaddr(NULL, farend, farendlen);
DEBUGMSGTL(("netsnmp_tcp", "accept succeeded (from %s)\n", str));
free(str);
@@ -238,6 +251,7 @@
netsnmp_tcp_transport(struct sockaddr_in *addr, int local)
{
netsnmp_transport *t = NULL;
+ netsnmp_udp_addr_pair *addr_pair = NULL;
int rc = 0;
@@ -251,13 +265,14 @@
}
memset(t, 0, sizeof(netsnmp_transport));
- t->data = malloc(sizeof(struct sockaddr_in));
- if (t->data == NULL) {
+ addr_pair = (netsnmp_udp_addr_pair *)malloc(sizeof(netsnmp_udp_addr_pair));
+ if (addr_pair == NULL) {
netsnmp_transport_free(t);
return NULL;
}
- t->data_length = sizeof(struct sockaddr_in);
- memcpy(t->data, addr, sizeof(struct sockaddr_in));
+ t->data = addr_pair;
+ t->data_length = sizeof(netsnmp_udp_addr_pair);
+ memcpy(&(addr_pair->remote_addr), addr, sizeof(struct sockaddr_in));
t->domain = netsnmp_snmpTCPDomain;
t->domain_length =
diff -ur net-snmp-5.3.1/snmplib/snmpUDPDomain.c net-snmp-5.3.1-fixed/snmplib/snmpUDPDomain.c
--- net-snmp-5.3.1/snmplib/snmpUDPDomain.c 2005-11-05 23:01:42.000000000 +0100
+++ net-snmp-5.3.1-fixed/snmplib/snmpUDPDomain.c 2007-02-09 20:53:10.626567462 +0100
@@ -64,6 +64,11 @@
static netsnmp_tdomain udpDomain;
+typedef struct netsnmp_udp_addr_pair_s {
+ struct sockaddr_in remote_addr;
+ struct in_addr local_addr;
+} netsnmp_udp_addr_pair;
+
/*
* not static, since snmpUDPIPv6Domain needs it, but not public, either.
* (ie don't put it in a public header.)
@@ -78,17 +83,23 @@
static char *
netsnmp_udp_fmtaddr(netsnmp_transport *t, void *data, int len)
{
- struct sockaddr_in *to = NULL;
+ netsnmp_udp_addr_pair *addr_pair = NULL;
- if (data != NULL && len == sizeof(struct sockaddr_in)) {
- to = (struct sockaddr_in *) data;
+ if (data != NULL && len == sizeof(netsnmp_udp_addr_pair)) {
+ addr_pair = (netsnmp_udp_addr_pair *) data;
} else if (t != NULL && t->data != NULL) {
- to = (struct sockaddr_in *) t->data;
+ addr_pair = (netsnmp_udp_addr_pair *) t->data;
}
- if (to == NULL) {
+
+ if (addr_pair == NULL) {
return strdup("UDP: unknown");
} else {
+ struct sockaddr_in *to = NULL;
char tmp[64];
+ to = (struct sockaddr_in *) &(addr_pair->remote_addr);
+ if (to == NULL) {
+ return strdup("UDP: unknown");
+ }
sprintf(tmp, "UDP: [%s]:%hu",
inet_ntoa(to->sin_addr), ntohs(to->sin_port));
@@ -98,6 +109,77 @@
+#ifdef IP_PKTINFO
+
+# define netsnmp_dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))
+
+static int netsnmp_udp_recvfrom(int s, char *buf, int len, struct sockaddr *from, int *fromlen, struct in_addr *dstip)
+{
+ int r;
+ struct iovec iov[1];
+ char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
+ struct cmsghdr *cmsgptr;
+ struct msghdr msg;
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = len;
+
+ memset(&msg, 0, sizeof msg);
+ msg.msg_name = from;
+ msg.msg_namelen = *fromlen;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &cmsg;
+ msg.msg_controllen = sizeof(cmsg);
+
+ r = recvmsg(s, &msg, 0);
+
+ if (r == -1) {
+ return -1;
+ }
+
+ DEBUGMSGTL(("netsnmp_udp", "got source addr: %s\n", inet_ntoa(((struct sockaddr_in *)from)->sin_addr)));
+ for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
+ if (cmsgptr->cmsg_level == SOL_IP && cmsgptr->cmsg_type == IP_PKTINFO) {
+ memcpy((void *) dstip, netsnmp_dstaddr(cmsgptr), sizeof(struct in_addr));
+ DEBUGMSGTL(("netsnmp_udp", "got destination (local) addr %s\n",
+ inet_ntoa(*dstip)));
+ }
+ }
+ return r;
+}
+
+static int netsnmp_udp_sendto(int fd, struct in_addr *srcip, struct sockaddr *remote,
+ char *data, int len)
+{
+ struct iovec iov = { data, len };
+ struct {
+ struct cmsghdr cm;
+ struct in_pktinfo ipi;
+ } cmsg = {
+ .cm = {
+ .cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo),
+ .cmsg_level = SOL_IP,
+ .cmsg_type = IP_PKTINFO,
+ },
+ .ipi = {
+ .ipi_ifindex = 0,
+ .ipi_spec_dst = srcip ? srcip->s_addr : 0,
+ },
+ };
+ struct msghdr m = {
+ .msg_name = remote,
+ .msg_namelen = sizeof(struct sockaddr_in),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = &cmsg,
+ .msg_controllen = sizeof(cmsg),
+ .msg_flags = 0,
+ };
+ return sendmsg(fd, &m, MSG_NOSIGNAL|MSG_DONTWAIT);
+}
+#endif /* IP_PKTINFO */
+
/*
* You can write something into opaque that will subsequently get passed back
* to your send function if you like. For instance, you might want to
@@ -110,27 +192,33 @@
{
int rc = -1;
socklen_t fromlen = sizeof(struct sockaddr);
+ netsnmp_udp_addr_pair *addr_pair = NULL;
struct sockaddr *from;
if (t != NULL && t->sock >= 0) {
- from = (struct sockaddr *) malloc(sizeof(struct sockaddr_in));
- if (from == NULL) {
+ addr_pair = (netsnmp_udp_addr_pair *) malloc(sizeof(netsnmp_udp_addr_pair));
+ if (addr_pair == NULL) {
*opaque = NULL;
*olength = 0;
return -1;
} else {
- memset(from, 0, fromlen);
+ memset(addr_pair, 0, sizeof(netsnmp_udp_addr_pair));
+ from = (struct sockaddr *) &(addr_pair->remote_addr);
}
while (rc < 0) {
- rc = recvfrom(t->sock, buf, size, 0, from, &fromlen);
+#if defined IP_PKTINFO
+ rc = netsnmp_udp_recvfrom(t->sock, buf, size, from, &fromlen, &(addr_pair->local_addr));
+#else
+ rc = recvfrom(t->sock, buf, size, 0, from, &fromlen);
+#endif /* IP_PKTINFO */
if (rc < 0 && errno != EINTR) {
break;
}
}
if (rc >= 0) {
- char *str = netsnmp_udp_fmtaddr(NULL, from, fromlen);
+ char *str = netsnmp_udp_fmtaddr(NULL, addr_pair, sizeof(netsnmp_udp_addr_pair));
DEBUGMSGTL(("netsnmp_udp",
"recvfrom fd %d got %d bytes (from %s)\n",
t->sock, rc, str));
@@ -139,8 +227,8 @@
DEBUGMSGTL(("netsnmp_udp", "recvfrom fd %d err %d (\"%s\")\n",
t->sock, errno, strerror(errno)));
}
- *opaque = (void *)from;
- *olength = sizeof(struct sockaddr_in);
+ *opaque = (void *)addr_pair;
+ *olength = sizeof(netsnmp_udp_addr_pair);
}
return rc;
}
@@ -152,24 +240,31 @@
void **opaque, int *olength)
{
int rc = -1;
+ netsnmp_udp_addr_pair *addr_pair = NULL;
struct sockaddr *to = NULL;
if (opaque != NULL && *opaque != NULL &&
- *olength == sizeof(struct sockaddr_in)) {
- to = (struct sockaddr *) (*opaque);
+ *olength == sizeof(netsnmp_udp_addr_pair)) {
+ addr_pair = (netsnmp_udp_addr_pair *) (*opaque);
} else if (t != NULL && t->data != NULL &&
- t->data_length == sizeof(struct sockaddr_in)) {
- to = (struct sockaddr *) (t->data);
+ t->data_length == sizeof(netsnmp_udp_addr_pair)) {
+ addr_pair = (netsnmp_udp_addr_pair *) (t->data);
}
+ to = (struct sockaddr *) &(addr_pair->remote_addr);
+
if (to != NULL && t != NULL && t->sock >= 0) {
- char *str = netsnmp_udp_fmtaddr(NULL, (void *) to,
- sizeof(struct sockaddr_in));
+ char *str = netsnmp_udp_fmtaddr(NULL, (void *) addr_pair,
+ sizeof(netsnmp_udp_addr_pair));
DEBUGMSGTL(("netsnmp_udp", "send %d bytes from %p to %s on fd %d\n",
size, buf, str, t->sock));
free(str);
while (rc < 0) {
- rc = sendto(t->sock, buf, size, 0, to, sizeof(struct sockaddr));
+#if defined IP_PKTINFO
+ rc = netsnmp_udp_sendto(t->sock, addr_pair ? &(addr_pair->local_addr) : NULL, to, buf, size);
+#else
+ rc = sendto(t->sock, buf, size, 0, to, sizeof(struct sockaddr));
+#endif /* IP_PKTINFO */
if (rc < 0 && errno != EINTR) {
DEBUGMSGTL(("netsnmp_udp", "sendto error, rc %d (errno %d)\n",
rc, errno));
@@ -486,18 +581,26 @@
int rc = 0;
char *str = NULL;
char *client_socket = NULL;
+ netsnmp_udp_addr_pair *addr_pair = NULL;
if (addr == NULL || addr->sin_family != AF_INET) {
return NULL;
}
+ addr_pair = (struct udp_addr_pair *) malloc(sizeof(netsnmp_udp_addr_pair));
+ if (addr_pair == NULL) {
+ return NULL;
+ }
+ memset(addr_pair, 0, sizeof(netsnmp_udp_addr_pair));
+ memcpy(&(addr_pair->remote_addr), addr, sizeof(struct sockaddr_in));
+
t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
if (t == NULL) {
return NULL;
}
- str = netsnmp_udp_fmtaddr(NULL, (void *)addr,
- sizeof(struct sockaddr_in));
+ str = netsnmp_udp_fmtaddr(NULL, (void *)addr_pair,
+ sizeof(netsnmp_udp_addr_pair));
DEBUGMSGTL(("netsnmp_udp", "open %s %s:%d\n", local ? "local" : "remote",
str,addr->sin_port));
free(str);
@@ -532,6 +635,18 @@
t->local[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
t->local_length = 6;
+#ifdef IP_PKTINFO
+ {
+ int sockopt = 1;
+ int sockoptlen = sizeof(int);
+ if (setsockopt(t->sock, SOL_IP, IP_PKTINFO, &sockopt, sizeof sockopt) == -1) {
+ DEBUGMSGTL(("netsnmp_udp", "couldn't set IP_PKTINFO: %s\n",
+ strerror(errno)));
+ return NULL;
+ }
+ DEBUGMSGTL(("netsnmp_udp", "set IP_PKTINFO\n"));
+ }
+#endif
rc = bind(t->sock, (struct sockaddr *) addr,
sizeof(struct sockaddr));
if (rc != 0) {
@@ -561,7 +676,7 @@
* transport-specific data pointer for later use by netsnmp_udp_send.
*/
- t->data = malloc(sizeof(struct sockaddr_in));
+ t->data = malloc(sizeof(netsnmp_udp_addr_pair));
t->remote = malloc(6);
if (t->data == NULL || t->remote == NULL) {
netsnmp_transport_free(t);
@@ -571,8 +686,8 @@
t->remote[4] = (htons(addr->sin_port) & 0xff00) >> 8;
t->remote[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
t->remote_length = 6;
- memcpy(t->data, addr, sizeof(struct sockaddr_in));
- t->data_length = sizeof(struct sockaddr_in);
+ memcpy(t->data, addr_pair, sizeof(netsnmp_udp_addr_pair));
+ t->data_length = sizeof(netsnmp_udp_addr_pair);
}
/*
@@ -993,7 +1108,8 @@
char **contextName)
{
com2SecEntry *c;
- struct sockaddr_in *from = (struct sockaddr_in *) opaque;
+ netsnmp_udp_addr_pair *addr_pair = (netsnmp_udp_addr_pair *) opaque;
+ struct sockaddr_in *from = (struct sockaddr_in *) &(addr_pair->remote_addr);
char *ztcommunity = NULL;
if (secName != NULL) {
@@ -1015,7 +1131,7 @@
* name.
*/
- if (opaque == NULL || olength != sizeof(struct sockaddr_in) ||
+ if (opaque == NULL || olength != sizeof(netsnmp_udp_addr_pair) ||
from->sin_family != AF_INET) {
DEBUGMSGTL(("netsnmp_udp_getSecName",
"no IPv4 source address in PDU?\n"));
More information about the Pkg-net-snmp-devel
mailing list