jabberd2  2.7.0
access.c
Go to the documentation of this file.
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 
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 
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 
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 
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 
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 
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 
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 
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 }
uint8_t s6_addr[16]
IPv6 address.
Definition: util_compat.h:70
access_rule_t deny
Definition: util.h:243
struct sockaddr_storage ip
Definition: util.h:232
int nallow
Definition: util.h:241
int access_deny(access_t access, const char *ip, const char *mask)
Definition: access.c:184
int j_inet_pton(const char *src, struct sockaddr_storage *dst)
set the address of a struct sockaddr_storage (modeled after the stdlib function inet_pton) ...
Definition: inaddr.c:46
struct access_rule_st * access_rule_t
access_t access_new(int order)
Definition: access.c:26
int order
Definition: util.h:238
sa_family_t ss_family
address family
Definition: util_compat.h:99
static int _access_check_match(struct sockaddr_storage *ip_1, struct sockaddr_storage *ip_2, int netsize)
check if two ip addresses are within the same subnet
Definition: access.c:79
int j_atoi(const char *a, int def)
Definition: str.c:87
static int _access_calc_netsize(const char *mask, int defaultsize)
Definition: access.c:42
void access_free(access_t access)
Definition: access.c:35
int mask
Definition: util.h:233
int ndeny
Definition: util.h:244
#define IN6_IS_ADDR_V4MAPPED(a)
check if an IPv6 is just a mapped IPv4 address
Definition: util_compat.h:54
access_rule_t allow
Definition: util.h:240
static void _access_unmap_v4(struct sockaddr_in6 *src, struct sockaddr_in *dst)
convert a IPv6 mapped IPv4 address to a real IPv4 address
Definition: access.c:71
int access_allow(access_t access, const char *ip, const char *mask)
Definition: access.c:164
int access_check(access_t access, const char *ip)
Definition: access.c:204
structure that contains an IPv6 including some additional attributes (only defined if not contained i...
Definition: util_compat.h:79
struct access_st * access_t
#define AF_INET6
address family for IPv6
Definition: util_compat.h:42
struct in6_addr sin6_addr
IPv6 address.
Definition: util_compat.h:86