1 /*
2 Copyright (c) 2004-2012 NFG Net Facilities Group BV support@nfg.nl
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later
8 version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "dbmail.h"
21
22 #define THIS_MODULE "cidr"
23
24 #define T Cidr_T
25
26 struct T {
27 char *sock_str;
28 struct sockaddr_in *socket;
29 short int mask;
30 const char repr[FIELDSIZE];
31 };
32
cidr_new(const char * str)33 T cidr_new(const char *str)
34 {
35 T self;
36 char *addr, *port, *mask;
37 char *haddr, *hport;
38 unsigned i;
39 size_t l;
40
41 assert(str != NULL);
42
43 self = (T)g_malloc0(sizeof(*self));
44 self->sock_str = g_strdup(str);
45 self->socket = (struct sockaddr_in *)g_malloc0(sizeof(struct sockaddr_in));
46 self->mask = 32;
47
48 addr = g_strdup(str);
49 haddr = addr;
50 while (*addr && *addr != ':')
51 addr++;
52 if (*addr == ':')
53 addr++;
54
55 port = g_strdup(addr);
56 hport = port;
57 while (*port && *port != ':')
58 port++;
59 if (*port == ':')
60 port++;
61
62 /* chop port */
63 l = strlen(addr);
64 for (i=0; i<l; i++) {
65 if (addr[i] == ':') {
66 addr[i]='\0';
67 break;
68 }
69 }
70
71 mask = index(addr,'/');
72 if (mask && mask[1] != '\0') {
73 mask++;
74 self->mask = atoi(mask);
75
76 /* chop mask */
77 l = strlen(addr);
78 for(i=0; i<l; i++) {
79 if (addr[i] == '/') {
80 addr[i]='\0';
81 break;
82 }
83 }
84 }
85
86
87 self->socket->sin_family = AF_INET;
88 self->socket->sin_port = strtol(port,NULL,10);
89 if (! inet_aton(addr,&self->socket->sin_addr)) {
90 g_free(haddr);
91 g_free(hport);
92 cidr_free(&self);
93 return NULL;
94 }
95
96 if (self->socket->sin_addr.s_addr == 0)
97 self->mask = 0;
98
99 g_free(haddr);
100 g_free(hport);
101
102 g_snprintf((char *)self->repr, FIELDSIZE-1, "struct cidrfilter {\n"
103 "\tsock_str: %s;\n"
104 "\tsocket->sin_addr: %s;\n"
105 "\tsocket->sin_port: %d;\n"
106 "\tmask: %d;\n"
107 "};\n",
108 self->sock_str,
109 inet_ntoa(self->socket->sin_addr),
110 self->socket->sin_port,
111 self->mask
112 );
113
114 TRACE(TRACE_DEBUG,"%s", cidr_repr(self));
115 return self;
116 }
117
cidr_repr(T self)118 const char * cidr_repr(T self)
119 {
120 return self->repr;
121 }
122
cidr_match(T base,T test)123 int cidr_match(T base, T test)
124 {
125 char *fullmask = "255.255.255.255";
126 struct in_addr match_addr, base_addr, test_addr;
127 inet_aton(fullmask, &base_addr);
128 inet_aton(fullmask, &test_addr);
129 unsigned result = 0;
130
131 if (base->mask)
132 base_addr.s_addr = ~((unsigned long)base_addr.s_addr >> (32-base->mask));
133 if (test->mask)
134 test_addr.s_addr = ~((unsigned long)test_addr.s_addr >> (32-test->mask));
135
136 base_addr.s_addr = (base->socket->sin_addr.s_addr | base_addr.s_addr);
137 test_addr.s_addr = (test->socket->sin_addr.s_addr | test_addr.s_addr);
138 match_addr.s_addr = (base_addr.s_addr & test_addr.s_addr);
139
140 /* only match ports if specified */
141 if (test->socket->sin_port > 0 && (base->socket->sin_port != test->socket->sin_port))
142 return 0;
143
144 if (test_addr.s_addr == match_addr.s_addr)
145 result = base->mask ? base->mask : 32;
146
147 if ((! base->mask) || (! test->mask))
148 result = 32;
149
150 return result;
151
152 }
153
cidr_free(T * self)154 void cidr_free(T *self)
155 {
156 T s = *self;
157 if (! s) return;
158
159 if (s->socket)
160 g_free(s->socket);
161 if (s->sock_str)
162 g_free(s->sock_str);
163 if (s) g_free(s);
164
165 s = NULL;
166 }
167
168