/src/net-snmp/snmplib/transports/snmpIPBaseDomain.c
Line | Count | Source |
1 | | #include <net-snmp/net-snmp-config.h> |
2 | | #include <net-snmp/types.h> |
3 | | #include <net-snmp/output_api.h> |
4 | | #include <net-snmp/library/system.h> |
5 | | #include "snmpIPBaseDomain.h" |
6 | | #include <ctype.h> |
7 | | #include <errno.h> |
8 | | #include <stdlib.h> |
9 | | #include <string.h> |
10 | | |
11 | | static int netsnmp_isnumber(const char *cp) |
12 | 10.4k | { |
13 | 10.4k | if (!*cp) |
14 | 688 | return 0; |
15 | | |
16 | 9.79k | while (isdigit((unsigned char)*cp)) |
17 | 16.3k | cp++; |
18 | 9.79k | return *cp == '\0'; |
19 | 10.4k | } |
20 | | |
21 | | /** |
22 | | * Parse a Net-SNMP endpoint name. |
23 | | * @ep_str: Parsed endpoint name. |
24 | | * @endpoint: Endpoint specification in the format |
25 | | * <address>[@<iface>]:[<port>], <address>[@<iface>] or <port>. |
26 | | * |
27 | | * Only overwrite those fields of *@ep_str that have been set in |
28 | | * @endpoint. Returns 1 upon success and 0 upon failure. |
29 | | */ |
30 | | int netsnmp_parse_ep_str(struct netsnmp_ep_str *ep_str, const char *endpoint) |
31 | 6.04k | { |
32 | 6.04k | char *dup, *cp, *addrstr = NULL, *iface = NULL, *portstr = NULL; |
33 | 6.04k | unsigned port; |
34 | | |
35 | 6.04k | if (!endpoint) |
36 | 0 | return 0; |
37 | | |
38 | 6.04k | dup = strdup(endpoint); |
39 | 6.04k | if (!dup) |
40 | 0 | return 0; |
41 | | |
42 | 6.04k | cp = dup; |
43 | 6.04k | if (netsnmp_isnumber(cp)) { |
44 | 81 | portstr = cp; |
45 | 5.96k | } else { |
46 | 5.96k | if (*cp == '[') { |
47 | 53 | addrstr = cp + 1; |
48 | 53 | cp = strchr(cp, ']'); |
49 | 53 | if (cp) { |
50 | 46 | cp[0] = '\0'; |
51 | 46 | cp++; |
52 | 46 | } else { |
53 | 7 | goto err; |
54 | 7 | } |
55 | 5.90k | } else if (*cp != '@' && (*cp != ':' || cp[1] == ':')) { |
56 | 1.44k | addrstr = cp; |
57 | 1.44k | cp = strchr(addrstr, '@'); |
58 | 1.44k | if (!cp) { |
59 | 1.36k | cp = strrchr(addrstr, ':'); |
60 | 1.36k | if (cp && strchr(dup, ':') < cp) |
61 | 49 | cp = NULL; |
62 | 1.36k | } |
63 | 1.44k | } |
64 | 5.95k | if (cp && *cp == '@') { |
65 | 235 | *cp = '\0'; |
66 | 235 | iface = cp + 1; |
67 | 235 | cp = strchr(cp + 1, ':'); |
68 | 235 | } |
69 | 5.95k | if (cp && *cp == ':') { |
70 | 4.44k | *cp++ = '\0'; |
71 | 4.44k | portstr = cp; |
72 | 4.44k | if (!netsnmp_isnumber(cp)) |
73 | 70 | goto err; |
74 | 4.44k | } else if (cp && *cp) { |
75 | 24 | goto err; |
76 | 24 | } |
77 | 5.95k | } |
78 | | |
79 | 5.94k | if (addrstr) { |
80 | 1.41k | ep_str->addr = strdup(addrstr); |
81 | 1.41k | if (!ep_str->addr) |
82 | 0 | goto err; |
83 | 1.41k | } |
84 | 5.94k | if (iface) |
85 | 230 | strlcpy(ep_str->iface, iface, sizeof(ep_str->iface)); |
86 | 5.94k | if (portstr) { |
87 | 4.45k | port = atoi(portstr); |
88 | 4.45k | if (port <= 0xffff) |
89 | 4.42k | strlcpy(ep_str->port, portstr, sizeof(ep_str->port)); |
90 | 32 | else |
91 | 32 | goto err; |
92 | 4.45k | } |
93 | | |
94 | 5.90k | free(dup); |
95 | 5.90k | return 1; |
96 | | |
97 | 133 | err: |
98 | 133 | free(ep_str->addr); |
99 | 133 | ep_str->addr = NULL; |
100 | 133 | free(dup); |
101 | 133 | return 0; |
102 | 5.94k | } |
103 | | |
104 | | int netsnmp_bindtodevice(int fd, const char *iface) |
105 | 3.44k | { |
106 | | /* If no interface name has been specified, report success. */ |
107 | 3.44k | if (!iface || iface[0] == '\0') |
108 | 3.44k | return 0; |
109 | | |
110 | 0 | #ifdef HAVE_SO_BINDTODEVICE |
111 | 0 | { |
112 | | /* |
113 | | * +1 to work around the Linux kernel bug that the passed in name is not |
114 | | * '\0'-terminated. |
115 | | */ |
116 | 0 | int ifacelen = strlen(iface) + 1; |
117 | 0 | int ret; |
118 | |
|
119 | 0 | ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, iface, ifacelen); |
120 | 0 | if (ret < 0) |
121 | 0 | snmp_log(LOG_ERR, "Binding socket to interface %s failed: %s\n", |
122 | 0 | iface, strerror(errno)); |
123 | 0 | return ret; |
124 | 3.44k | } |
125 | | #else |
126 | | errno = EINVAL; |
127 | | return -1; |
128 | | #endif |
129 | 3.44k | } |
130 | | |
131 | | int netsnmp_ipbase_session_init(struct netsnmp_transport_s *transport, |
132 | 3.44k | struct snmp_session *sess) { |
133 | 3.44k | union { |
134 | 3.44k | struct sockaddr sa; |
135 | 3.44k | struct sockaddr_in sin; |
136 | 3.44k | struct sockaddr_in6 sin6; |
137 | 3.44k | } ss; |
138 | 3.44k | socklen_t len = sizeof(ss); |
139 | | |
140 | 3.44k | if (!sess) { |
141 | 0 | DEBUGMSGTL(("netsnmp_ipbase", "session pointer is NULL\n")); |
142 | 0 | return SNMPERR_SUCCESS; |
143 | 0 | } |
144 | | |
145 | 3.44k | if (getsockname(transport->sock, (struct sockaddr *)&ss, &len) == -1) { |
146 | 0 | DEBUGMSGTL(("netsnmp_ipbase", "getsockname error %s\n", strerror(errno))); |
147 | 0 | return SNMPERR_SUCCESS; |
148 | 0 | } |
149 | 3.44k | switch (ss.sa.sa_family) { |
150 | 3.44k | case AF_INET: |
151 | 3.44k | sess->local_port = ntohs(ss.sin.sin_port); |
152 | 3.44k | break; |
153 | 0 | case AF_INET6: |
154 | 0 | sess->local_port = ntohs(ss.sin6.sin6_port); |
155 | 0 | break; |
156 | 0 | default: |
157 | 0 | DEBUGMSGTL(("netsnmp_ipbase", "unsupported address family %d\n", |
158 | 0 | ss.sa.sa_family)); |
159 | 0 | return SNMPERR_SUCCESS; |
160 | 3.44k | } |
161 | | |
162 | 3.44k | DEBUGMSGTL(("netsnmp_ipbase", "local port number %d\n", sess->local_port)); |
163 | | |
164 | 3.44k | return SNMPERR_SUCCESS; |
165 | 3.44k | } |