Coverage Report

Created: 2026-04-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}