1 /*
2 * jabberd - Jabber Open Source Server
3 * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4 * Ryan Eatmon, Robert Norris
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19 */
20
21 /* this implements allow/deny filters for IP address */
22
23 #include "util.h"
24 #include <arpa/inet.h>
25
access_new(int order)26 access_t access_new(int order)
27 {
28 access_t access = (access_t) calloc(1, sizeof(struct access_st));
29
30 access->order = order;
31
32 return access;
33 }
34
access_free(access_t access)35 void access_free(access_t access)
36 {
37 if(access->allow != NULL) free(access->allow);
38 if(access->deny != NULL) free(access->deny);
39 free(access);
40 }
41
_access_calc_netsize(const char * mask,int defaultsize)42 static int _access_calc_netsize(const char *mask, int defaultsize)
43 {
44 struct in_addr legacy_mask;
45 int netsize;
46
47 #ifndef HAVE_INET_PTON
48 if(strchr(mask, '.') && inet_aton(mask, &legacy_mask))
49 #else
50 if(inet_pton(AF_INET, mask, &legacy_mask.s_addr) > 0)
51 #endif
52 {
53 /* netmask has been given in dotted decimal form */
54 int temp = ntohl(legacy_mask.s_addr);
55 netsize = 32;
56
57 while(netsize && temp%2==0)
58 {
59 netsize--;
60 temp /= 2;
61 }
62 } else {
63 /* numerical netsize */
64 netsize = j_atoi(mask, defaultsize);
65 }
66
67 return netsize;
68 }
69
70 /** convert a IPv6 mapped IPv4 address to a real IPv4 address */
_access_unmap_v4(struct sockaddr_in6 * src,struct sockaddr_in * dst)71 static void _access_unmap_v4(struct sockaddr_in6 *src, struct sockaddr_in *dst)
72 {
73 memset(dst, 0, sizeof(struct sockaddr_in));
74 dst->sin_family = AF_INET;
75 dst->sin_addr.s_addr = htonl((((int)src->sin6_addr.s6_addr[12]*256+src->sin6_addr.s6_addr[13])*256+src->sin6_addr.s6_addr[14])*256+(int)src->sin6_addr.s6_addr[15]);
76 }
77
78 /** check if two ip addresses are within the same subnet */
_access_check_match(struct sockaddr_storage * ip_1,struct sockaddr_storage * ip_2,int netsize)79 static int _access_check_match(struct sockaddr_storage *ip_1, struct sockaddr_storage *ip_2, int netsize)
80 {
81 struct sockaddr_in *sin_1;
82 struct sockaddr_in *sin_2;
83 struct sockaddr_in6 *sin6_1;
84 struct sockaddr_in6 *sin6_2;
85 int i;
86
87 sin_1 = (struct sockaddr_in *)ip_1;
88 sin_2 = (struct sockaddr_in *)ip_2;
89 sin6_1 = (struct sockaddr_in6 *)ip_1;
90 sin6_2 = (struct sockaddr_in6 *)ip_2;
91
92 /* addresses of different families */
93 if(ip_1->ss_family != ip_2->ss_family)
94 {
95 /* maybe on of the addresses is just a IPv6 mapped IPv4 address */
96 if (ip_1->ss_family == AF_INET && ip_2->ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6_2->sin6_addr))
97 {
98 struct sockaddr_storage t;
99 struct sockaddr_in *temp;
100
101 temp = (struct sockaddr_in *)&t;
102
103 _access_unmap_v4(sin6_2, temp);
104 if(netsize>96)
105 netsize -= 96;
106
107 return _access_check_match(ip_1, &t, netsize);
108 }
109
110 if (ip_1->ss_family == AF_INET6 && ip_2->ss_family == AF_INET && IN6_IS_ADDR_V4MAPPED(&sin6_1->sin6_addr))
111 {
112 struct sockaddr_storage t;
113 struct sockaddr_in *temp;
114
115 temp = (struct sockaddr_in *)&t;
116
117 _access_unmap_v4(sin6_1, temp);
118 if(netsize>96)
119 netsize -= 96;
120
121 return _access_check_match(&t, ip_2, netsize);
122 }
123
124 return 0;
125 }
126
127 /* IPv4? */
128 if(ip_1->ss_family == AF_INET)
129 {
130 int netmask;
131
132 if(netsize > 32)
133 netsize = 32;
134
135 netmask = htonl(((uint32_t)-1) << (32-netsize));
136
137 return ((sin_1->sin_addr.s_addr&netmask) == (sin_2->sin_addr.s_addr&netmask));
138 }
139
140 /* IPv6? */
141 if(ip_1->ss_family == AF_INET6)
142 {
143 unsigned char bytemask;
144
145 if(netsize > 128)
146 netsize = 128;
147
148 for(i=0; i<netsize/8; i++)
149 if(sin6_1->sin6_addr.s6_addr[i] != sin6_2->sin6_addr.s6_addr[i])
150 return 0;
151
152 if(netsize%8 == 0)
153 return 1;
154
155 bytemask = 0xff << (8 - netsize%8);
156
157 return ((sin6_1->sin6_addr.s6_addr[i]&bytemask) == (sin6_2->sin6_addr.s6_addr[i]&bytemask));
158 }
159
160 /* unknown address family */
161 return 0;
162 }
163
access_allow(access_t access,const char * ip,const char * mask)164 int access_allow(access_t access, const char *ip, const char *mask)
165 {
166 struct sockaddr_storage ip_addr;
167 int netsize;
168
169 if(j_inet_pton(ip, &ip_addr) <= 0)
170 return 1;
171
172 netsize = _access_calc_netsize(mask, ip_addr.ss_family==AF_INET ? 32 : 128);
173
174 access->allow = (access_rule_t) realloc(access->allow, sizeof(struct access_rule_st) * (access->nallow + 1));
175
176 memcpy(&access->allow[access->nallow].ip, &ip_addr, sizeof(ip_addr));
177 access->allow[access->nallow].mask = netsize;
178
179 access->nallow++;
180
181 return 0;
182 }
183
access_deny(access_t access,const char * ip,const char * mask)184 int access_deny(access_t access, const char *ip, const char *mask)
185 {
186 struct sockaddr_storage ip_addr;
187 int netsize;
188
189 if(j_inet_pton(ip, &ip_addr) <= 0)
190 return 1;
191
192 netsize = _access_calc_netsize(mask, ip_addr.ss_family==AF_INET ? 32 : 128);
193
194 access->deny = (access_rule_t) realloc(access->deny, sizeof(struct access_rule_st) * (access->ndeny + 1));
195
196 memcpy(&access->deny[access->ndeny].ip, &ip_addr, sizeof(ip_addr));
197 access->deny[access->ndeny].mask = netsize;
198
199 access->ndeny++;
200
201 return 0;
202 }
203
access_check(access_t access,const char * ip)204 int access_check(access_t access, const char *ip)
205 {
206 struct sockaddr_storage addr;
207 access_rule_t rule;
208 int i, allow = 0, deny = 0;
209
210 if(j_inet_pton(ip, &addr) <= 0)
211 return 0;
212
213 /* first, search the allow list */
214 for(i = 0; !allow && i < access->nallow; i++)
215 {
216 rule = &access->allow[i];
217 if(_access_check_match(&addr, &rule->ip, rule->mask))
218 allow = 1;
219 }
220
221 /* now the deny list */
222 for(i = 0; !deny && i < access->ndeny; i++)
223 {
224 rule = &access->deny[i];
225 if(_access_check_match(&addr, &rule->ip, rule->mask))
226 deny = 1;
227 }
228
229 /* allow then deny */
230 if(access->order == 0)
231 {
232 if(allow)
233 return 1;
234
235 if(deny)
236 return 0;
237
238 /* allow by default */
239 return 1;
240 }
241
242 /* deny then allow */
243 if(deny)
244 return 0;
245
246 if(allow)
247 return 1;
248
249 /* deny by default */
250 return 0;
251 }
252