Annotation of embedaddon/miniupnpd/pf/pfpinhole.c, revision 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>