1: /* $Id: upnppermissions.c,v 1.1.1.2 2013/07/22 00:32:35 misho Exp $ */
2: /* MiniUPnP project
3: * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4: * (c) 2006-2012 Thomas Bernard
5: * This software is subject to the conditions detailed
6: * in the LICENCE file provided within the distribution */
7:
8: #include <ctype.h>
9: #include <string.h>
10: #include <stdlib.h>
11: #include <stdio.h>
12: #include <syslog.h>
13: #include <netinet/in.h>
14: #include <arpa/inet.h>
15: #include <unistd.h>
16: #include "config.h"
17: #include "upnppermissions.h"
18:
19: /* read_permission_line()
20: * parse the a permission line which format is :
21: * (deny|allow) [0-9]+(-[0-9]+) ip/mask [0-9]+(-[0-9]+)
22: * ip/mask is either 192.168.1.1/24 or 192.168.1.1/255.255.255.0
23: */
24: int
25: read_permission_line(struct upnpperm * perm,
26: char * p)
27: {
28: char * q;
29: int n_bits;
30: int i;
31:
32: /* first token: (allow|deny) */
33: while(isspace(*p))
34: p++;
35: if(0 == memcmp(p, "allow", 5))
36: {
37: perm->type = UPNPPERM_ALLOW;
38: p += 5;
39: }
40: else if(0 == memcmp(p, "deny", 4))
41: {
42: perm->type = UPNPPERM_DENY;
43: p += 4;
44: }
45: else
46: {
47: return -1;
48: }
49: while(isspace(*p))
50: p++;
51:
52: /* second token: eport or eport_min-eport_max */
53: if(!isdigit(*p))
54: return -1;
55: for(q = p; isdigit(*q); q++);
56: if(*q=='-')
57: {
58: *q = '\0';
59: i = atoi(p);
60: if(i > 65535)
61: return -1;
62: perm->eport_min = (u_short)i;
63: q++;
64: p = q;
65: while(isdigit(*q))
66: q++;
67: *q = '\0';
68: i = atoi(p);
69: if(i > 65535)
70: return -1;
71: perm->eport_max = (u_short)i;
72: if(perm->eport_min > perm->eport_max)
73: return -1;
74: }
75: else if(isspace(*q))
76: {
77: *q = '\0';
78: i = atoi(p);
79: if(i > 65535)
80: return -1;
81: perm->eport_min = perm->eport_max = (u_short)i;
82: }
83: else
84: {
85: return -1;
86: }
87: p = q + 1;
88: while(isspace(*p))
89: p++;
90:
91: /* third token: ip/mask */
92: if(!isdigit(*p))
93: return -1;
94: for(q = p; isdigit(*q) || (*q == '.'); q++);
95: if(*q=='/')
96: {
97: *q = '\0';
98: if(!inet_aton(p, &perm->address))
99: return -1;
100: q++;
101: p = q;
102: while(isdigit(*q))
103: q++;
104: if(*q == '.')
105: {
106: while(*q == '.' || isdigit(*q))
107: q++;
108: if(!isspace(*q))
109: return -1;
110: *q = '\0';
111: if(!inet_aton(p, &perm->mask))
112: return -1;
113: }
114: else if(!isspace(*q))
115: return -1;
116: else
117: {
118: *q = '\0';
119: n_bits = atoi(p);
120: if(n_bits > 32)
121: return -1;
122: perm->mask.s_addr = htonl(n_bits ? (0xffffffffu << (32 - n_bits)) : 0);
123: }
124: }
125: else if(isspace(*q))
126: {
127: *q = '\0';
128: if(!inet_aton(p, &perm->address))
129: return -1;
130: perm->mask.s_addr = 0xffffffffu;
131: }
132: else
133: {
134: return -1;
135: }
136: p = q + 1;
137:
138: /* fourth token: iport or iport_min-iport_max */
139: while(isspace(*p))
140: p++;
141: if(!isdigit(*p))
142: return -1;
143: for(q = p; isdigit(*q); q++);
144: if(*q=='-')
145: {
146: *q = '\0';
147: i = atoi(p);
148: if(i > 65535)
149: return -1;
150: perm->iport_min = (u_short)i;
151: q++;
152: p = q;
153: while(isdigit(*q))
154: q++;
155: *q = '\0';
156: i = atoi(p);
157: if(i > 65535)
158: return -1;
159: perm->iport_max = (u_short)i;
160: if(perm->iport_min > perm->iport_max)
161: return -1;
162: }
163: else if(isspace(*q) || *q == '\0')
164: {
165: *q = '\0';
166: i = atoi(p);
167: if(i > 65535)
168: return -1;
169: perm->iport_min = perm->iport_max = (u_short)i;
170: }
171: else
172: {
173: return -1;
174: }
175: #ifdef DEBUG
176: printf("perm rule added : %s %hu-%hu %08x/%08x %hu-%hu\n",
177: (perm->type==UPNPPERM_ALLOW)?"allow":"deny",
178: perm->eport_min, perm->eport_max, ntohl(perm->address.s_addr),
179: ntohl(perm->mask.s_addr), perm->iport_min, perm->iport_max);
180: #endif
181: return 0;
182: }
183:
184: #ifdef USE_MINIUPNPDCTL
185: void
186: write_permlist(int fd, const struct upnpperm * permary,
187: int nperms)
188: {
189: int l;
190: const struct upnpperm * perm;
191: int i;
192: char buf[128];
193: write(fd, "Permissions :\n", 14);
194: for(i = 0; i<nperms; i++)
195: {
196: perm = permary + i;
197: l = snprintf(buf, sizeof(buf), "%02d %s %hu-%hu %08x/%08x %hu-%hu\n",
198: i,
199: (perm->type==UPNPPERM_ALLOW)?"allow":"deny",
200: perm->eport_min, perm->eport_max, ntohl(perm->address.s_addr),
201: ntohl(perm->mask.s_addr), perm->iport_min, perm->iport_max);
202: if(l<0)
203: return;
204: write(fd, buf, l);
205: }
206: }
207: #endif
208:
209: /* match_permission()
210: * returns: 1 if eport, address, iport matches the permission rule
211: * 0 if no match */
212: static int
213: match_permission(const struct upnpperm * perm,
214: u_short eport, struct in_addr address, u_short iport)
215: {
216: if( (eport < perm->eport_min) || (perm->eport_max < eport))
217: return 0;
218: if( (iport < perm->iport_min) || (perm->iport_max < iport))
219: return 0;
220: if( (address.s_addr & perm->mask.s_addr)
221: != (perm->address.s_addr & perm->mask.s_addr) )
222: return 0;
223: return 1;
224: }
225:
226: int
227: check_upnp_rule_against_permissions(const struct upnpperm * permary,
228: int n_perms,
229: u_short eport, struct in_addr address,
230: u_short iport)
231: {
232: int i;
233: for(i=0; i<n_perms; i++)
234: {
235: if(match_permission(permary + i, eport, address, iport))
236: {
237: syslog(LOG_DEBUG,
238: "UPnP permission rule %d matched : port mapping %s",
239: i, (permary[i].type == UPNPPERM_ALLOW)?"accepted":"rejected"
240: );
241: return (permary[i].type == UPNPPERM_ALLOW);
242: }
243: }
244: syslog(LOG_DEBUG, "no permission rule matched : accept by default (n_perms=%d)", n_perms);
245: return 1; /* Default : accept */
246: }
247:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>