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