Annotation of embedaddon/miniupnpd/pf/pfpinhole.c, revision 1.1.1.1
1.1 misho 1: /* $Id: pfpinhole.c,v 1.19 2012/05/21 15:47:57 nanard Exp $ */
2: /* MiniUPnP project
3: * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4: * (c) 2012 Thomas Bernard
5: * This software is subject to the conditions detailed
6: * in the LICENCE file provided within the distribution */
7:
8: #include <sys/types.h>
9: #include <sys/socket.h>
10: #include <sys/param.h>
11: #include <net/if.h>
12: #include <netinet/in.h>
13: #include <netinet/tcp.h>
14: #include <arpa/inet.h>
15: #ifdef __DragonFly__
16: #include <net/pf/pfvar.h>
17: #else
18: #include <net/pfvar.h>
19: #endif
20: #include <fcntl.h>
21: #include <sys/ioctl.h>
22: #include <unistd.h>
23: #include <string.h>
24: #include <syslog.h>
25: #include <stdio.h>
26: #include <stdlib.h>
27:
28: #include "../config.h"
29: #include "pfpinhole.h"
30: #include "../upnpglobalvars.h"
31:
32: /* the pass rules created by add_pinhole() are as follow :
33: *
34: * pass in quick on ep0 inet6 proto udp
35: * from any to dead:beef::42:42 port = 8080
36: * flags S/SA keep state
37: * label "pinhole-2 ts-4321000"
38: *
39: * with the label "pinhole-$uid ts-$timestamp"
40: */
41:
42: #ifdef ENABLE_6FC_SERVICE
43: /* /dev/pf when opened */
44: extern int dev;
45:
46: static int next_uid = 1;
47:
48: #define PINEHOLE_LABEL_FORMAT "pinhole-%d ts-%u"
49:
50: int add_pinhole(const char * ifname,
51: const char * rem_host, unsigned short rem_port,
52: const char * int_client, unsigned short int_port,
53: int proto, unsigned int timestamp)
54: {
55: int uid;
56: struct pfioc_rule pcr;
57: #ifndef PF_NEWSTYLE
58: struct pfioc_pooladdr pp;
59: #endif
60:
61: if(dev<0) {
62: syslog(LOG_ERR, "pf device is not open");
63: return -1;
64: }
65: memset(&pcr, 0, sizeof(pcr));
66: strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
67:
68: #ifndef PF_NEWSTYLE
69: memset(&pp, 0, sizeof(pp));
70: strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
71: if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0) {
72: syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
73: return -1;
74: } else {
75: pcr.pool_ticket = pp.ticket;
76: #else
77: {
78: #endif
79: pcr.rule.direction = PF_IN;
80: pcr.rule.action = PF_PASS;
81: pcr.rule.af = AF_INET6;
82: #ifdef PF_NEWSTYLE
83: pcr.rule.nat.addr.type = PF_ADDR_NONE;
84: pcr.rule.rdr.addr.type = PF_ADDR_NONE;
85: #endif
86: #ifdef USE_IFNAME_IN_RULES
87: if(ifname)
88: strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
89: #endif
90: pcr.rule.proto = proto;
91:
92: pcr.rule.quick = 1;/*(GETFLAG(PFNOQUICKRULESMASK))?0:1;*/
93: pcr.rule.log = (GETFLAG(LOGPACKETSMASK))?1:0; /*logpackets;*/
94: /* see the discussion on the forum :
95: * http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=638 */
96: pcr.rule.flags = TH_SYN;
97: pcr.rule.flagset = (TH_SYN|TH_ACK);
98: #ifdef PFRULE_HAS_RTABLEID
99: pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */
100: #endif
101: #ifdef PFRULE_HAS_ONRDOMAIN
102: pcr.rule.onrdomain = -1; /* first appeared in OpenBSD 5.0 */
103: #endif
104: pcr.rule.keep_state = 1;
105: uid = next_uid;
106: snprintf(pcr.rule.label, PF_RULE_LABEL_SIZE,
107: PINEHOLE_LABEL_FORMAT, uid, timestamp);
108: if(queue)
109: strlcpy(pcr.rule.qname, queue, PF_QNAME_SIZE);
110: if(tag)
111: strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE);
112:
113: if(rem_port) {
114: pcr.rule.src.port_op = PF_OP_EQ;
115: pcr.rule.src.port[0] = htons(rem_port);
116: }
117: if(rem_host && rem_host[0] != '\0' && rem_host[0] != '*') {
118: pcr.rule.src.addr.type = PF_ADDR_ADDRMASK;
119: if(inet_pton(AF_INET6, rem_host, &pcr.rule.src.addr.v.a.addr.v6) != 1) {
120: syslog(LOG_ERR, "inet_pton(%s) failed", rem_host);
121: }
122: memset(&pcr.rule.src.addr.v.a.mask.addr8, 255, 16);
123: }
124:
125: pcr.rule.dst.port_op = PF_OP_EQ;
126: pcr.rule.dst.port[0] = htons(int_port);
127: pcr.rule.dst.addr.type = PF_ADDR_ADDRMASK;
128: if(inet_pton(AF_INET6, int_client, &pcr.rule.dst.addr.v.a.addr.v6) != 1) {
129: syslog(LOG_ERR, "inet_pton(%s) failed", int_client);
130: }
131: memset(&pcr.rule.dst.addr.v.a.mask.addr8, 255, 16);
132:
133: if(ifname)
134: strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
135:
136: pcr.action = PF_CHANGE_GET_TICKET;
137: if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) {
138: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
139: return -1;
140: } else {
141: pcr.action = PF_CHANGE_ADD_TAIL;
142: if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) {
143: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
144: return -1;
145: }
146: }
147: }
148:
149: if(++next_uid >= 65535) {
150: next_uid = 1;
151: }
152: return uid;
153: }
154:
155: int delete_pinhole(unsigned short uid)
156: {
157: int i, n;
158: struct pfioc_rule pr;
159: char label_start[PF_RULE_LABEL_SIZE];
160: char tmp_label[PF_RULE_LABEL_SIZE];
161:
162: if(dev<0) {
163: syslog(LOG_ERR, "pf device is not open");
164: return -1;
165: }
166: snprintf(label_start, sizeof(label_start),
167: "pinhole-%hu", uid);
168: memset(&pr, 0, sizeof(pr));
169: strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
170: #ifndef PF_NEWSTYLE
171: pr.rule.action = PF_PASS;
172: #endif
173: if(ioctl(dev, DIOCGETRULES, &pr) < 0) {
174: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
175: return -1;
176: }
177: n = pr.nr;
178: for(i=0; i<n; i++) {
179: pr.nr = i;
180: if(ioctl(dev, DIOCGETRULE, &pr) < 0) {
181: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
182: return -1;
183: }
184: strlcpy(tmp_label, pr.rule.label, sizeof(tmp_label));
185: strtok(tmp_label, " ");
186: if(0 == strcmp(tmp_label, label_start)) {
187: pr.action = PF_CHANGE_GET_TICKET;
188: if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) {
189: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
190: return -1;
191: }
192: pr.action = PF_CHANGE_REMOVE;
193: pr.nr = i;
194: if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) {
195: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
196: return -1;
197: }
198: return 0;
199: }
200: }
201: /* not found */
202: return -2;
203: }
204:
205: int
206: get_pinhole_info(unsigned short uid,
207: char * rem_host, int rem_hostlen, unsigned short * rem_port,
208: char * int_client, int int_clientlen, unsigned short * int_port,
209: int * proto, unsigned int * timestamp,
210: u_int64_t * packets, u_int64_t * bytes)
211: {
212: int i, n;
213: struct pfioc_rule pr;
214: char label_start[PF_RULE_LABEL_SIZE];
215: char tmp_label[PF_RULE_LABEL_SIZE];
216: char * p;
217:
218: if(dev<0) {
219: syslog(LOG_ERR, "pf device is not open");
220: return -1;
221: }
222: snprintf(label_start, sizeof(label_start),
223: "pinhole-%hu", uid);
224: memset(&pr, 0, sizeof(pr));
225: strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
226: #ifndef PF_NEWSTYLE
227: pr.rule.action = PF_PASS;
228: #endif
229: if(ioctl(dev, DIOCGETRULES, &pr) < 0) {
230: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
231: return -1;
232: }
233: n = pr.nr;
234: for(i=0; i<n; i++) {
235: pr.nr = i;
236: if(ioctl(dev, DIOCGETRULE, &pr) < 0) {
237: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
238: return -1;
239: }
240: strlcpy(tmp_label, pr.rule.label, sizeof(tmp_label));
241: p = tmp_label;
242: strsep(&p, " ");
243: if(0 == strcmp(tmp_label, label_start)) {
244: if(rem_host && (inet_ntop(AF_INET6, &pr.rule.src.addr.v.a.addr.v6, rem_host, rem_hostlen) == NULL)) {
245: return -1;
246: }
247: if(rem_port)
248: *rem_port = ntohs(pr.rule.src.port[0]);
249: if(int_client && (inet_ntop(AF_INET6, &pr.rule.dst.addr.v.a.addr.v6, int_client, int_clientlen) == NULL)) {
250: return -1;
251: }
252: if(int_port)
253: *int_port = ntohs(pr.rule.dst.port[0]);
254: if(proto)
255: *proto = pr.rule.proto;
256: if(timestamp)
257: sscanf(p, "ts-%u", timestamp);
258: #ifdef PFRULE_INOUT_COUNTS
259: if(packets)
260: *packets = pr.rule.packets[0] + pr.rule.packets[1];
261: if(bytes)
262: *bytes = pr.rule.bytes[0] + pr.rule.bytes[1];
263: #else
264: if(packets)
265: *packets = pr.rule.packets;
266: if(bytes)
267: *bytes = pr.rule.bytes;
268: #endif
269: return 0;
270: }
271: }
272: /* not found */
273: return -2;
274: }
275:
276: int update_pinhole(unsigned short uid, unsigned int timestamp)
277: {
278: /* TODO :
279: * As it is not possible to change rule label, we should :
280: * 1 - delete
281: * 2 - Add new
282: * the stats of the rule will then be reset :( */
283: return -42; /* not implemented */
284: }
285:
286: /* return the number of rules removed
287: * or a negative integer in case of error */
288: int clean_pinhole_list(unsigned int * next_timestamp)
289: {
290: int i;
291: struct pfioc_rule pr;
292: time_t current_time;
293: unsigned int ts;
294: int uid;
295: unsigned int min_ts = UINT_MAX;
296: int min_uid = INT_MAX, max_uid = -1;
297: int n = 0;
298:
299: if(dev<0) {
300: syslog(LOG_ERR, "pf device is not open");
301: return -1;
302: }
303: current_time = time(NULL);
304: memset(&pr, 0, sizeof(pr));
305: strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
306: #ifndef PF_NEWSTYLE
307: pr.rule.action = PF_PASS;
308: #endif
309: if(ioctl(dev, DIOCGETRULES, &pr) < 0) {
310: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
311: return -1;
312: }
313: for(i = pr.nr - 1; i >= 0; i--) {
314: pr.nr = i;
315: if(ioctl(dev, DIOCGETRULE, &pr) < 0) {
316: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
317: return -1;
318: }
319: if(sscanf(pr.rule.label, PINEHOLE_LABEL_FORMAT, &uid, &ts) != 2) {
320: syslog(LOG_INFO, "rule with label '%s' is not a IGD pinhole", pr.rule.label);
321: continue;
322: }
323: if(ts <= (unsigned int)current_time) {
324: syslog(LOG_INFO, "removing expired pinhole '%s'", pr.rule.label);
325: pr.action = PF_CHANGE_GET_TICKET;
326: if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) {
327: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
328: return -1;
329: }
330: pr.action = PF_CHANGE_REMOVE;
331: pr.nr = i;
332: if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) {
333: syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
334: return -1;
335: }
336: n++;
337: #ifndef PF_NEWSTYLE
338: pr.rule.action = PF_PASS;
339: #endif
340: if(ioctl(dev, DIOCGETRULES, &pr) < 0) {
341: syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
342: return -1;
343: }
344: } else {
345: if(uid > max_uid)
346: max_uid = uid;
347: else if(uid < min_uid)
348: min_uid = uid;
349: if(ts < min_ts)
350: min_ts = ts;
351: }
352: }
353: if(next_timestamp && (min_ts != UINT_MAX))
354: *next_timestamp = min_ts;
355: if(max_uid > 0) {
356: if(((min_uid - 32000) <= next_uid) && (next_uid <= max_uid)) {
357: next_uid = max_uid + 1;
358: }
359: if(next_uid >= 65535) {
360: next_uid = 1;
361: }
362: }
363: return n; /* number of rules removed */
364: }
365:
366: #endif /* ENABLE_IPV6 */
367:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>