xref: /openbsd/usr.sbin/npppd/common/net_utils.c (revision 64f4079b)
1 /*	$OpenBSD: net_utils.c,v 1.6 2020/12/30 18:52:06 benno 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.6 2020/12/30 18:52:06 benno 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 *
get_ifname_by_sockaddr(struct sockaddr * sa,char * ifname)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 == NULL ||
54 		    addr->ifa_addr->sa_family != sa->sa_family ||
55 		    addr->ifa_addr->sa_len != sa->sa_len)
56 			continue;
57 		switch (addr->ifa_addr->sa_family) {
58 		default:
59 			continue;
60 		case AF_INET:
61 			in4a = &((struct sockaddr_in *)addr->ifa_addr)
62 			    ->sin_addr;
63 			in4b = &((struct sockaddr_in *)sa)->sin_addr;
64 			if (in4a->s_addr == in4b->s_addr) {
65 				strlcpy(ifname, addr->ifa_name, IF_NAMESIZE);
66 				ifname0 = ifname;
67 			}
68 			break;
69 		case AF_INET6:
70 			in6a = &((struct sockaddr_in6 *)addr->ifa_addr)
71 			    ->sin6_addr;
72 			in6b = &((struct sockaddr_in6 *)sa)->sin6_addr;
73 			if (IN6_ARE_ADDR_EQUAL(in6a, in6b)) {
74 				strlcpy(ifname, addr->ifa_name, IF_NAMESIZE);
75 				ifname0 = ifname;
76 			}
77 			break;
78 		}
79 	}
80 	freeifaddrs(addr0);
81 
82 	return ifname0;
83 }
84 
85 /**
86  * Convert argument like "192.168.160.1:1723/tcp" or "[::1]:1723/tcp" to
87  * match getaddrinfo(3)'s specification and pass them to getaddrinfo(3).
88  */
89 int
addrport_parse(const char * addrport,int proto,struct addrinfo ** p_ai)90 addrport_parse(const char *addrport, int proto, struct addrinfo **p_ai)
91 {
92 	char buf[256];
93 	char *servp, *nodep, *slash;
94 	struct addrinfo hints;
95 
96 	strlcpy(buf, addrport, sizeof(buf));
97 	if (buf[0] == '[' && (servp = strchr(buf, ']')) != NULL) {
98 		nodep = buf + 1;
99 		*servp++ = '\0';
100 		if (*servp != ':')
101 			servp = NULL;
102 	} else {
103 		nodep = buf;
104 		servp = strrchr(nodep, ':');
105 	}
106 	if (servp != NULL) {
107 		*servp = '\0';
108 		servp++;
109 		slash = strrchr(servp, '/');
110 		if (slash != NULL) {
111 			/*
112 			 * Ignore like "/tcp"
113 			 */
114 			*slash = '\0';
115 			slash++;
116 		}
117 	} else
118 		servp = NULL;
119 	memset(&hints, 0, sizeof(hints));
120 	hints.ai_flags = AI_NUMERICHOST;
121 	hints.ai_family = AF_UNSPEC;
122 	switch (proto) {
123 	case IPPROTO_TCP:
124 		hints.ai_socktype = SOCK_STREAM;
125 		break;
126 	case IPPROTO_UDP:
127 		hints.ai_socktype = SOCK_DGRAM;
128 		break;
129 	}
130 	hints.ai_protocol = proto;
131 
132 	return getaddrinfo(nodep, servp, &hints, p_ai);
133 }
134 
135 /**
136  * Make a string like "192.168.160.1:1723" or "[::1]:1723" from a struct
137  * sockaddr
138  *
139  * @param	buf	the buffer to be stored a string
140  * @param	lbuf	the length of the buf
141  */
142 const char *
addrport_tostring(struct sockaddr * sa,socklen_t salen,char * buf,int lbuf)143 addrport_tostring(struct sockaddr *sa, socklen_t salen, char *buf, int lbuf)
144 {
145 	char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
146 
147 	if (getnameinfo(sa, salen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
148 	    NI_NUMERICHOST | NI_NUMERICSERV) != 0)
149 		return NULL;
150 
151 	switch (sa->sa_family) {
152 	case AF_INET6:
153 		strlcpy(buf, "[", lbuf);
154 		strlcat(buf, hbuf, lbuf);
155 		strlcat(buf, "]:", lbuf);
156 		strlcat(buf, sbuf, lbuf);
157 		break;
158 	case AF_INET:
159 		strlcpy(buf, hbuf, lbuf);
160 		strlcat(buf, ":", lbuf);
161 		strlcat(buf, sbuf, lbuf);
162 		break;
163 	default:
164 		return NULL;
165 	}
166 
167 	return buf;
168 }
169 
170 /** Convert 32bit IPv4 netmask to the prefix length in host byte order */
171 int
netmask2prefixlen(uint32_t mask)172 netmask2prefixlen(uint32_t mask)
173 {
174     switch(mask) {
175     case 0x00000000:  return  0;
176     case 0x80000000:  return  1;
177     case 0xC0000000:  return  2;
178     case 0xE0000000:  return  3;
179     case 0xF0000000:  return  4;
180     case 0xF8000000:  return  5;
181     case 0xFC000000:  return  6;
182     case 0xFE000000:  return  7;
183     case 0xFF000000:  return  8;
184     case 0xFF800000:  return  9;
185     case 0xFFC00000:  return 10;
186     case 0xFFE00000:  return 11;
187     case 0xFFF00000:  return 12;
188     case 0xFFF80000:  return 13;
189     case 0xFFFC0000:  return 14;
190     case 0xFFFE0000:  return 15;
191     case 0xFFFF0000:  return 16;
192     case 0xFFFF8000:  return 17;
193     case 0xFFFFC000:  return 18;
194     case 0xFFFFE000:  return 19;
195     case 0xFFFFF000:  return 20;
196     case 0xFFFFF800:  return 21;
197     case 0xFFFFFC00:  return 22;
198     case 0xFFFFFE00:  return 23;
199     case 0xFFFFFF00:  return 24;
200     case 0xFFFFFF80:  return 25;
201     case 0xFFFFFFC0:  return 26;
202     case 0xFFFFFFE0:  return 27;
203     case 0xFFFFFFF0:  return 28;
204     case 0xFFFFFFF8:  return 29;
205     case 0xFFFFFFFC:  return 30;
206     case 0xFFFFFFFE:  return 31;
207     case 0xFFFFFFFF:  return 32;
208     }
209     return -1;
210 }
211