1 |
|
|
/* $OpenBSD: net_utils.c,v 1.5 2015/12/17 08:01:55 tb Exp $ */ |
2 |
|
|
/*- |
3 |
|
|
* Copyright (c) 2009 Internet Initiative Japan Inc. |
4 |
|
|
* All rights reserved. |
5 |
|
|
* |
6 |
|
|
* Redistribution and use in source and binary forms, with or without |
7 |
|
|
* modification, are permitted provided that the following conditions |
8 |
|
|
* are met: |
9 |
|
|
* 1. Redistributions of source code must retain the above copyright |
10 |
|
|
* notice, this list of conditions and the following disclaimer. |
11 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer in the |
13 |
|
|
* documentation and/or other materials provided with the distribution. |
14 |
|
|
* |
15 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
|
|
* SUCH DAMAGE. |
26 |
|
|
*/ |
27 |
|
|
/* $Id: net_utils.c,v 1.5 2015/12/17 08:01:55 tb Exp $ */ |
28 |
|
|
#include <sys/types.h> |
29 |
|
|
#include <sys/socket.h> |
30 |
|
|
#include <netinet/in.h> |
31 |
|
|
#include <net/if.h> |
32 |
|
|
#include <ifaddrs.h> |
33 |
|
|
#include <netdb.h> |
34 |
|
|
#include <stdlib.h> |
35 |
|
|
#include <string.h> |
36 |
|
|
|
37 |
|
|
#include "net_utils.h" |
38 |
|
|
|
39 |
|
|
/** Get an interface name from sockaddr */ |
40 |
|
|
const char * |
41 |
|
|
get_ifname_by_sockaddr(struct sockaddr *sa, char *ifname) |
42 |
|
|
{ |
43 |
|
|
struct ifaddrs *addr, *addr0; |
44 |
|
|
struct in_addr *in4a, *in4b; |
45 |
|
|
const char *ifname0 = NULL; |
46 |
|
|
struct in6_addr *in6a, *in6b; |
47 |
|
|
|
48 |
|
|
ifname0 = NULL; |
49 |
|
|
/* I want other way than linear search */ |
50 |
|
|
getifaddrs(&addr0); |
51 |
|
|
for (addr = addr0; ifname0 == NULL&& addr != NULL; |
52 |
|
|
addr = addr->ifa_next) { |
53 |
|
|
if (addr->ifa_addr->sa_family != sa->sa_family || |
54 |
|
|
addr->ifa_addr->sa_len != sa->sa_len) |
55 |
|
|
continue; |
56 |
|
|
switch (addr->ifa_addr->sa_family) { |
57 |
|
|
default: |
58 |
|
|
continue; |
59 |
|
|
case AF_INET: |
60 |
|
|
in4a = &((struct sockaddr_in *)addr->ifa_addr) |
61 |
|
|
->sin_addr; |
62 |
|
|
in4b = &((struct sockaddr_in *)sa)->sin_addr; |
63 |
|
|
if (in4a->s_addr == in4b->s_addr) { |
64 |
|
|
strlcpy(ifname, addr->ifa_name, IF_NAMESIZE); |
65 |
|
|
ifname0 = ifname; |
66 |
|
|
} |
67 |
|
|
break; |
68 |
|
|
case AF_INET6: |
69 |
|
|
in6a = &((struct sockaddr_in6 *)addr->ifa_addr) |
70 |
|
|
->sin6_addr; |
71 |
|
|
in6b = &((struct sockaddr_in6 *)sa)->sin6_addr; |
72 |
|
|
if (IN6_ARE_ADDR_EQUAL(in6a, in6b)) { |
73 |
|
|
strlcpy(ifname, addr->ifa_name, IF_NAMESIZE); |
74 |
|
|
ifname0 = ifname; |
75 |
|
|
} |
76 |
|
|
break; |
77 |
|
|
} |
78 |
|
|
} |
79 |
|
|
freeifaddrs(addr0); |
80 |
|
|
|
81 |
|
|
return ifname0; |
82 |
|
|
} |
83 |
|
|
|
84 |
|
|
/** |
85 |
|
|
* Convert argument like "192.168.160.1:1723/tcp" or "[::1]:1723/tcp" to |
86 |
|
|
* match getaddrinfo(3)'s specification and pass them to getaddrinfo(3). |
87 |
|
|
*/ |
88 |
|
|
int |
89 |
|
|
addrport_parse(const char *addrport, int proto, struct addrinfo **p_ai) |
90 |
|
|
{ |
91 |
|
|
char buf[256]; |
92 |
|
|
char *servp, *nodep, *slash; |
93 |
|
|
struct addrinfo hints; |
94 |
|
|
|
95 |
|
|
strlcpy(buf, addrport, sizeof(buf)); |
96 |
|
|
if (buf[0] == '[' && (servp = strchr(buf, ']')) != NULL) { |
97 |
|
|
nodep = buf + 1; |
98 |
|
|
*servp++ = '\0'; |
99 |
|
|
if (*servp != ':') |
100 |
|
|
servp = NULL; |
101 |
|
|
} else { |
102 |
|
|
nodep = buf; |
103 |
|
|
servp = strrchr(nodep, ':'); |
104 |
|
|
} |
105 |
|
|
if (servp != NULL) { |
106 |
|
|
*servp = '\0'; |
107 |
|
|
servp++; |
108 |
|
|
slash = strrchr(servp, '/'); |
109 |
|
|
if (slash != NULL) { |
110 |
|
|
/* |
111 |
|
|
* Ignore like "/tcp" |
112 |
|
|
*/ |
113 |
|
|
*slash = '\0'; |
114 |
|
|
slash++; |
115 |
|
|
} |
116 |
|
|
} else |
117 |
|
|
servp = NULL; |
118 |
|
|
memset(&hints, 0, sizeof(hints)); |
119 |
|
|
hints.ai_flags = AI_NUMERICHOST; |
120 |
|
|
hints.ai_family = AF_UNSPEC; |
121 |
|
|
switch (proto) { |
122 |
|
|
case IPPROTO_TCP: |
123 |
|
|
hints.ai_socktype = SOCK_STREAM; |
124 |
|
|
break; |
125 |
|
|
case IPPROTO_UDP: |
126 |
|
|
hints.ai_socktype = SOCK_DGRAM; |
127 |
|
|
break; |
128 |
|
|
} |
129 |
|
|
hints.ai_protocol = proto; |
130 |
|
|
|
131 |
|
|
return getaddrinfo(nodep, servp, &hints, p_ai); |
132 |
|
|
} |
133 |
|
|
|
134 |
|
|
/** |
135 |
|
|
* Make a string like "192.168.160.1:1723" or "[::1]:1723" from a struct |
136 |
|
|
* sockaddr |
137 |
|
|
* |
138 |
|
|
* @param buf the buffer to be stored a string |
139 |
|
|
* @param lbuf the length of the buf |
140 |
|
|
*/ |
141 |
|
|
const char * |
142 |
|
|
addrport_tostring(struct sockaddr *sa, socklen_t salen, char *buf, int lbuf) |
143 |
|
|
{ |
144 |
|
|
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; |
145 |
|
|
|
146 |
|
|
if (getnameinfo(sa, salen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), |
147 |
|
|
NI_NUMERICHOST | NI_NUMERICSERV) != 0) |
148 |
|
|
return NULL; |
149 |
|
|
|
150 |
|
|
switch (sa->sa_family) { |
151 |
|
|
case AF_INET6: |
152 |
|
|
strlcpy(buf, "[", lbuf); |
153 |
|
|
strlcat(buf, hbuf, lbuf); |
154 |
|
|
strlcat(buf, "]:", lbuf); |
155 |
|
|
strlcat(buf, sbuf, lbuf); |
156 |
|
|
break; |
157 |
|
|
case AF_INET: |
158 |
|
|
strlcpy(buf, hbuf, lbuf); |
159 |
|
|
strlcat(buf, ":", lbuf); |
160 |
|
|
strlcat(buf, sbuf, lbuf); |
161 |
|
|
break; |
162 |
|
|
default: |
163 |
|
|
return NULL; |
164 |
|
|
} |
165 |
|
|
|
166 |
|
|
return buf; |
167 |
|
|
} |
168 |
|
|
|
169 |
|
|
/** Convert 32bit IPv4 netmask to the prefix length in host byte order */ |
170 |
|
|
int |
171 |
|
|
netmask2prefixlen(uint32_t mask) |
172 |
|
|
{ |
173 |
|
|
switch(mask) { |
174 |
|
|
case 0x00000000: return 0; |
175 |
|
|
case 0x80000000: return 1; |
176 |
|
|
case 0xC0000000: return 2; |
177 |
|
|
case 0xE0000000: return 3; |
178 |
|
|
case 0xF0000000: return 4; |
179 |
|
|
case 0xF8000000: return 5; |
180 |
|
|
case 0xFC000000: return 6; |
181 |
|
|
case 0xFE000000: return 7; |
182 |
|
|
case 0xFF000000: return 8; |
183 |
|
|
case 0xFF800000: return 9; |
184 |
|
|
case 0xFFC00000: return 10; |
185 |
|
|
case 0xFFE00000: return 11; |
186 |
|
|
case 0xFFF00000: return 12; |
187 |
|
|
case 0xFFF80000: return 13; |
188 |
|
|
case 0xFFFC0000: return 14; |
189 |
|
|
case 0xFFFE0000: return 15; |
190 |
|
|
case 0xFFFF0000: return 16; |
191 |
|
|
case 0xFFFF8000: return 17; |
192 |
|
|
case 0xFFFFC000: return 18; |
193 |
|
|
case 0xFFFFE000: return 19; |
194 |
|
|
case 0xFFFFF000: return 20; |
195 |
|
|
case 0xFFFFF800: return 21; |
196 |
|
|
case 0xFFFFFC00: return 22; |
197 |
|
|
case 0xFFFFFE00: return 23; |
198 |
|
|
case 0xFFFFFF00: return 24; |
199 |
|
|
case 0xFFFFFF80: return 25; |
200 |
|
|
case 0xFFFFFFC0: return 26; |
201 |
|
|
case 0xFFFFFFE0: return 27; |
202 |
|
|
case 0xFFFFFFF0: return 28; |
203 |
|
|
case 0xFFFFFFF8: return 29; |
204 |
|
|
case 0xFFFFFFFC: return 30; |
205 |
|
|
case 0xFFFFFFFE: return 31; |
206 |
|
|
case 0xFFFFFFFF: return 32; |
207 |
|
|
} |
208 |
|
|
return -1; |
209 |
|
|
} |