1 /* grecs - Gray's Extensible Configuration System
2    Copyright (C) 2007-2016 Sergey Poznyakoff
3 
4    Grecs is free software; you can redistribute it and/or modify it
5    under the terms of the GNU General Public License as published by the
6    Free Software Foundation; either version 3 of the License, or (at your
7    option) any later version.
8 
9    Grecs is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License along
15    with Grecs. If not, see <http://www.gnu.org/licenses/>. */
16 
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "grecs.h"
28 
29 static void
uint32_to_bytes(unsigned char * bytes,uint32_t u)30 uint32_to_bytes (unsigned char *bytes, uint32_t u)
31 {
32 	int i;
33 
34 	for (i = 0; i < 4; i++)	{
35 		bytes[i] = u & 0xff;
36 		u >>= 8;
37 	}
38 }
39 
40 int
grecs_inaddr_to_bytes(int af,void * buf,unsigned char * bytes)41 grecs_inaddr_to_bytes(int af, void *buf, unsigned char *bytes)
42 {
43 	uint32_t u;
44 
45 	switch (af) {
46 	case AF_INET:
47 		memcpy(&u, buf, sizeof u);
48 		uint32_to_bytes(bytes, u);
49 		return 4;
50 
51 	case AF_INET6:
52 		memcpy(bytes, buf, 16);
53 		return 16;
54 	}
55 	return 0;
56 }
57 
58 int
grecs_sockaddr_to_bytes(unsigned char * bytes,struct sockaddr const * sa)59 grecs_sockaddr_to_bytes(unsigned char *bytes, struct sockaddr const *sa)
60 {
61 	switch (sa->sa_family) {
62 	case AF_INET:
63 		uint32_to_bytes(bytes,
64 				((struct sockaddr_in*)sa)->sin_addr.s_addr);
65 		return 4;
66 
67 	case AF_INET6:
68 		memcpy(bytes, &((struct sockaddr_in6*)sa)->sin6_addr, 16);
69 		return 16;
70 	}
71 	return 0;
72 }
73 
74 int
grecs_sockaddr_to_cidr(struct grecs_cidr * cidr,const struct sockaddr * sa)75 grecs_sockaddr_to_cidr(struct grecs_cidr *cidr, const struct sockaddr *sa)
76 {
77 	unsigned char address[GRECS_INADDR_BYTES];
78 	int len;
79 	int i;
80 
81 	len = grecs_sockaddr_to_bytes(address, sa);
82 	if (len == 0)
83 		return -1;
84 	cidr->family = sa->sa_family;
85 	cidr->len = len;
86 	memcpy(cidr->address, address, sizeof(cidr->address));
87 	for (i = 0; i < GRECS_INADDR_BYTES; i++)
88 		cidr->netmask[i] = 0xff;
89 	return 0;
90 }
91 
92 static void
masklen_to_netmask(unsigned char * buf,size_t len,size_t masklen)93 masklen_to_netmask(unsigned char *buf, size_t len, size_t masklen)
94 {
95 	int i, cnt;
96 
97 	cnt = masklen / 8;
98 	for (i = 0; i < cnt; i++)
99 		buf[i] = 0xff;
100 	if (i == GRECS_INADDR_BYTES)
101 		return;
102 	cnt = 8 - masklen % 8;
103 	buf[i++] = (0xff >> cnt) << cnt;
104 	for (; i < GRECS_INADDR_BYTES; i++)
105 		buf[i] = 0;
106 }
107 
108 int
grecs_str_to_cidr(struct grecs_cidr * pcidr,const char * str,grecs_locus_t const * locus)109 grecs_str_to_cidr(struct grecs_cidr *pcidr, const char *str,
110 		  grecs_locus_t const *locus)
111 {
112 	int rc;
113 	char ipbuf[41];
114 	struct grecs_cidr cidr;
115 	char *p;
116 	size_t len;
117 	union {
118 		struct in_addr in;
119 		struct in6_addr in6;
120 	} inaddr;
121 
122 	p = strchr(str, '/');
123 	if (p)
124 		len = p - str;
125 	else
126 		len = strlen(str);
127 
128 	if (len > sizeof(ipbuf)) {
129 		grecs_error(locus, 0, _("invalid network mask: %s"),
130 			    str);
131 		return -1;
132 	}
133 
134 	memcpy(ipbuf, str, len);
135 	ipbuf[len] = 0;
136 
137 	if (grecs_str_is_ipv4(ipbuf))
138 		cidr.family = AF_INET;
139 	else if (grecs_str_is_ipv6(ipbuf))
140 		cidr.family = AF_INET6;
141 	else {
142 		grecs_error(locus, 0, _("unrecognized address family: %s"),
143 			    str);
144 		return -1;
145 	}
146 
147 	rc = inet_pton(cidr.family, ipbuf, &inaddr);
148 	if (rc == -1) {
149 		grecs_error(locus, 0, _("unrecognized address family: %s"),
150 			    str);
151 		return -1;
152 	} else if (rc != 1) {
153 		grecs_error(locus, 0, _("invalid network address: %s"),
154 			    str);
155 		return -1;
156 	}
157 
158 	cidr.len = grecs_inaddr_to_bytes(cidr.family, &inaddr, cidr.address);
159 	if (cidr.len == 0) {
160 		grecs_error(locus, 0, _("unrecognized address family: %s"),
161 			    str);
162 		return -1;
163 	}
164 
165 	if (p) {
166 		char *end;
167 		unsigned long masklen;
168 
169 		p++;
170 
171 		masklen = strtoul(p, &end, 10);
172 		if (*end == 0)
173 			masklen_to_netmask(cidr.netmask, cidr.len, masklen);
174 		else if ((cidr.family == AF_INET && grecs_str_is_ipv4(p))
175 			 || (cidr.family == AF_INET6
176 			     && grecs_str_is_ipv6(ipbuf))) {
177 			rc = inet_pton(cidr.family, p, &inaddr);
178 			if (rc != 1) {
179 				grecs_error(locus, 0, _("invalid network mask: %s"),
180 					    str);
181 				return -1;
182 			}
183 			grecs_inaddr_to_bytes(cidr.family, &inaddr,
184 					      cidr.netmask);
185 		} else {
186 			grecs_error(locus, 0, _("invalid network mask: %s"),
187 				    str);
188 			return -1;
189 		}
190 	} else
191 		masklen_to_netmask(cidr.netmask, cidr.len, cidr.len * 8);
192 
193 	memcpy(pcidr, &cidr, sizeof(*pcidr));
194 	return 0;
195 }
196 
197 int
grecs_cidr_match(struct grecs_cidr * a,struct grecs_cidr * b)198 grecs_cidr_match(struct grecs_cidr *a, struct grecs_cidr *b)
199 {
200 	int i;
201 
202 	if (a->family != b->family)
203 		return 1;
204 	for (i = 0; i < a->len; i++) {
205 		if (a->address[i] != (b->address[i] & a->netmask[i]))
206 			return 1;
207 	}
208 	return 0;
209 }
210 
211 int
grecs_sockadd_cidr_match(struct sockaddr * sa,struct grecs_cidr * cidr)212 grecs_sockadd_cidr_match(struct sockaddr *sa, struct grecs_cidr *cidr)
213 {
214 	struct grecs_cidr t;
215 	if (grecs_sockaddr_to_cidr(&t, sa))
216 		return 1;
217 	return grecs_cidr_match(cidr, &t);
218 }
219