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