jabberd2  2.2.16
util/access.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
00004  *                    Ryan Eatmon, Robert Norris
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00019  */
00020 
00021 /* this implements allow/deny filters for IP address */
00022 
00023 #include "util.h"
00024 
00025 access_t access_new(int order)
00026 {
00027     access_t access = (access_t) calloc(1, sizeof(struct access_st));
00028 
00029     access->order = order;
00030 
00031     return access;
00032 }
00033 
00034 void access_free(access_t access)
00035 {
00036     if(access->allow != NULL) free(access->allow);
00037     if(access->deny != NULL) free(access->deny);
00038     free(access);
00039 }
00040 
00041 static int _access_calc_netsize(const char *mask, int defaultsize)
00042 {
00043     struct in_addr legacy_mask;
00044     int netsize;
00045 
00046 #ifndef HAVE_INET_PTON
00047     if(strchr(mask, '.') && inet_aton(mask, &legacy_mask))
00048 #else
00049     if(inet_pton(AF_INET, mask, &legacy_mask.s_addr) > 0)
00050 #endif
00051     {
00052         /* netmask has been given in dotted decimal form */
00053         int temp = ntohl(legacy_mask.s_addr);
00054         netsize = 32;
00055 
00056         while(netsize && temp%2==0)
00057         {
00058             netsize--;
00059             temp /= 2;
00060         }
00061     } else {
00062         /* numerical netsize */
00063         netsize = j_atoi(mask, defaultsize);
00064     }
00065 
00066     return netsize;
00067 }
00068 
00070 static void _access_unmap_v4(struct sockaddr_in6 *src, struct sockaddr_in *dst)
00071 {
00072     memset(dst, 0, sizeof(struct sockaddr_in));
00073     dst->sin_family = AF_INET;
00074     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]);
00075 }
00076 
00078 static int _access_check_match(struct sockaddr_storage *ip_1, struct sockaddr_storage *ip_2, int netsize)
00079 {
00080     struct sockaddr_in *sin_1;
00081     struct sockaddr_in *sin_2;
00082     struct sockaddr_in6 *sin6_1;
00083     struct sockaddr_in6 *sin6_2;
00084     int i;
00085 
00086     sin_1 = (struct sockaddr_in *)ip_1;
00087     sin_2 = (struct sockaddr_in *)ip_2;
00088     sin6_1 = (struct sockaddr_in6 *)ip_1;
00089     sin6_2 = (struct sockaddr_in6 *)ip_2;
00090 
00091     /* addresses of different families */
00092     if(ip_1->ss_family != ip_2->ss_family)
00093     {
00094         /* maybe on of the addresses is just a IPv6 mapped IPv4 address */
00095         if (ip_1->ss_family == AF_INET && ip_2->ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6_2->sin6_addr))
00096         {
00097             struct sockaddr_storage t;
00098             struct sockaddr_in *temp;
00099 
00100             temp = (struct sockaddr_in *)&t;
00101 
00102             _access_unmap_v4(sin6_2, temp);
00103             if(netsize>96)
00104                 netsize -= 96;
00105 
00106             return _access_check_match(ip_1, &t, netsize);
00107         }
00108 
00109         if (ip_1->ss_family == AF_INET6 && ip_2->ss_family == AF_INET && IN6_IS_ADDR_V4MAPPED(&sin6_1->sin6_addr))
00110         {
00111             struct sockaddr_storage t;
00112             struct sockaddr_in *temp;
00113 
00114             temp = (struct sockaddr_in *)&t;
00115         
00116             _access_unmap_v4(sin6_1, temp);
00117             if(netsize>96)
00118                 netsize -= 96;
00119 
00120             return _access_check_match(&t, ip_2, netsize);
00121         }
00122 
00123         return 0;
00124     }
00125 
00126     /* IPv4? */
00127     if(ip_1->ss_family == AF_INET)
00128     {
00129         int netmask;
00130 
00131         if(netsize > 32)
00132             netsize = 32;
00133 
00134         netmask = htonl(-1 << (32-netsize));
00135 
00136         return ((sin_1->sin_addr.s_addr&netmask) == (sin_2->sin_addr.s_addr&netmask));
00137     }
00138 
00139     /* IPv6? */
00140     if(ip_1->ss_family == AF_INET6)
00141     {
00142         unsigned char bytemask;
00143 
00144         if(netsize > 128)
00145             netsize = 128;
00146 
00147         for(i=0; i<netsize/8; i++)
00148             if(sin6_1->sin6_addr.s6_addr[i] != sin6_2->sin6_addr.s6_addr[i])
00149                 return 0;
00150     
00151         if(netsize%8 == 0)
00152             return 1;
00153 
00154         bytemask = 0xff << (8 - netsize%8);
00155 
00156         return ((sin6_1->sin6_addr.s6_addr[i]&bytemask) == (sin6_2->sin6_addr.s6_addr[i]&bytemask));
00157     }
00158 
00159     /* unknown address family */
00160     return 0;
00161 }
00162 
00163 int access_allow(access_t access, char *ip, char *mask)
00164 {
00165     struct sockaddr_storage ip_addr;
00166     int netsize;
00167 
00168     if(j_inet_pton(ip, &ip_addr) <= 0)
00169         return 1;
00170 
00171     netsize = _access_calc_netsize(mask, ip_addr.ss_family==AF_INET ? 32 : 128);
00172 
00173     access->allow = (access_rule_t) realloc(access->allow, sizeof(struct access_rule_st) * (access->nallow + 1));
00174 
00175     memcpy(&access->allow[access->nallow].ip, &ip_addr, sizeof(ip_addr));
00176     access->allow[access->nallow].mask = netsize;
00177 
00178     access->nallow++;
00179 
00180     return 0;
00181 }
00182 
00183 int access_deny(access_t access, char *ip, char *mask)
00184 {
00185     struct sockaddr_storage ip_addr;
00186     int netsize;
00187 
00188     if(j_inet_pton(ip, &ip_addr) <= 0)
00189         return 1;
00190 
00191     netsize = _access_calc_netsize(mask, ip_addr.ss_family==AF_INET ? 32 : 128);
00192 
00193     access->deny = (access_rule_t) realloc(access->deny, sizeof(struct access_rule_st) * (access->ndeny + 1));
00194 
00195     memcpy(&access->deny[access->ndeny].ip, &ip_addr, sizeof(ip_addr));
00196     access->deny[access->ndeny].mask = netsize;
00197 
00198     access->ndeny++;
00199 
00200     return 0;
00201 }
00202 
00203 int access_check(access_t access, char *ip)
00204 {
00205     struct sockaddr_storage addr;
00206     access_rule_t rule;
00207     int i, allow = 0, deny = 0;
00208 
00209     if(j_inet_pton(ip, &addr) <= 0)
00210         return 0;
00211 
00212     /* first, search the allow list */
00213     for(i = 0; !allow && i < access->nallow; i++)
00214     {
00215         rule = &access->allow[i];
00216         if(_access_check_match(&addr, &rule->ip, rule->mask))
00217             allow = 1;
00218     }
00219 
00220     /* now the deny list */
00221     for(i = 0; !deny && i < access->ndeny; i++)
00222     {
00223         rule = &access->deny[i];
00224         if(_access_check_match(&addr, &rule->ip, rule->mask))
00225             deny = 1;
00226     }
00227 
00228     /* allow then deny */
00229     if(access->order == 0)
00230     {
00231         if(allow)
00232             return 1;
00233 
00234         if(deny)
00235             return 0;
00236 
00237         /* allow by default */
00238         return 1;
00239     }
00240 
00241     /* deny then allow */
00242     if(deny)
00243         return 0;
00244 
00245     if(allow)
00246         return 1;
00247 
00248     /* deny by default */
00249     return 0;
00250 }