From e0efe74a7c87f637b8448e535613710762215995 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 20 Apr 2012 16:53:34 +0200 Subject: [PATCH] AddPinhole() and DeletePinhole() works ! (only with pf) --- miniupnpd/Changelog.txt | 6 ++- miniupnpd/upnpredirect.c | 82 +++++++++++++++++----------------------- miniupnpd/upnpsoap.c | 61 ++++++++++++++++++++---------- 3 files changed, 80 insertions(+), 69 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 8d79dd5..0458306 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,4 +1,8 @@ -$Id: Changelog.txt,v 1.271 2012/04/18 23:44:35 nanard Exp $ +$Id: Changelog.txt,v 1.272 2012/04/20 14:38:38 nanard Exp $ + +2012/04/20: + Enough WANIPv6FirewallControl is implemented on pf so that AddPinhole() and + DeletePinhole() works ! 2012/04/19: First working experiment of IPv6 "pinhole" with pf diff --git a/miniupnpd/upnpredirect.c b/miniupnpd/upnpredirect.c index 71f637b..c61e882 100644 --- a/miniupnpd/upnpredirect.c +++ b/miniupnpd/upnpredirect.c @@ -1,4 +1,4 @@ -/* $Id: upnpredirect.c,v 1.64 2012/04/14 22:12:09 nanard Exp $ */ +/* $Id: upnpredirect.c,v 1.66 2012/04/20 14:38:38 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2012 Thomas Bernard @@ -27,6 +27,7 @@ #endif #if defined(USE_PF) #include "pf/obsdrdr.h" +#include "pf/pfpinhole.h" #endif #if defined(USE_IPF) #include "ipf/ipfrdr.h" @@ -626,6 +627,7 @@ upnp_check_outbound_pinhole(int proto, int * timeout) * -1 failed to add pinhole * -2 already created * -3 inbound pinhole disabled + * TODO : return uid on success (positive) or error value (negative) */ int upnp_add_inboundpinhole(const char * raddr, @@ -633,33 +635,34 @@ upnp_add_inboundpinhole(const char * raddr, const char * iaddr, unsigned short iport, const char * protocol, - const char * leaseTime, + unsigned int leasetime, int * uid) { - int r, s, t, lt=0; - char iaddr_old[40]="", proto[6]="", idfound[5]="", leaseTmp[12]; /* IPv6 Modification*/ - snprintf(proto, sizeof(proto), "%.5d", atoi(protocol)); - unsigned short iport_old = 0; - time_t current = time(NULL); + int r; #if 0 + char iaddr_old[40]="", idfound[5]=""; /* IPv6 Modification*/ + unsigned short iport_old = 0; +#endif + time_t current; + unsigned int timestamp; struct in6_addr address; /* IPv6 Modification*/ + int proto; + if(inet_pton(AF_INET6, iaddr, &address) < 0) /* IPv6 Modification */ { syslog(LOG_ERR, "inet_pton(%s) : %m", iaddr); return 0; } -#endif - + proto = atoi(protocol); /* for WANIPv6FirewallControl AddPinhole, the protocol argument + * is passed as an integer, not a string */ + current = time(NULL); + timestamp = current + leasetime; #if 0 r = get_rule_from_file(raddr, rport, iaddr_old, &iport_old, proto, 0, 0, idfound); #endif r = 0; - lt = (int) current + atoi(leaseTime); - snprintf(leaseTmp, sizeof(leaseTmp), "%d", lt); - printf("LeaseTime: %d / %d -> %s\n", atoi(leaseTime), (int)current, leaseTmp); - - printf("\tCompare addr: %s // port: %d\n\t to addr: %s // port: %d\n", iaddr, iport, iaddr_old, iport_old); +#if 0 if(r == 1 && strcmp(iaddr, iaddr_old)==0 && iport==iport_old) { syslog(LOG_INFO, "Pinhole for inbound traffic from [%s]:%hu to [%s]:%hu with protocol %s already done. Updating it.", raddr, rport, iaddr_old, iport_old, protocol); @@ -668,10 +671,17 @@ upnp_add_inboundpinhole(const char * raddr, return t; } else +#endif { - syslog(LOG_INFO, "Adding pinhole for inbound traffic from [%s]:%hu to [%s]:%hu with protocol %s and %s lease time.", raddr, rport, iaddr, iport, protocol, leaseTime); - s = upnp_add_inboundpinhole_internal(raddr, rport, iaddr, iport, protocol, uid); + syslog(LOG_INFO, "Adding pinhole for inbound traffic from [%s]:%hu to [%s]:%hu with protocol %s and %u lease time.", raddr, rport, iaddr, iport, protocol, leasetime); +#ifdef USE_PF + *uid = add_pinhole (0/*ext_if_name*/, raddr, rport, iaddr, iport, proto, timestamp); + return 1; +#else + return -42; /* not implemented */ +#endif #if 0 + s = upnp_add_inboundpinhole_internal(raddr, rport, iaddr, iport, protocol, uid); if(rule_file_add(raddr, rport, iaddr, iport, protocol, leaseTmp, uid)<0) return -8; else @@ -794,39 +804,15 @@ upnp_update_inboundpinhole(const char * uid, const char * leasetime) int upnp_delete_inboundpinhole(const char * uid) { - /* TODO : to be implemented */ -#if 0 - /* this is a alpha implementation calling ip6tables via system(), - * it can be usefull as an example to code the netfilter version */ - int r, s, linenum=0; - char cmd[256], cmd_raw[256]; - syslog(LOG_INFO, "Removing pinhole for inbound traffic with ID: %s", uid); - r = check_rule_from_file(uid, &linenum); - if(r > 0) - { - s = rule_file_remove(uid, linenum); - if(s < 0) - return s; - else - { - snprintf(cmd, sizeof(cmd), "ip6tables -t filter -D %s %d", miniupnpd_forward_chain, linenum); - snprintf(cmd_raw, sizeof(cmd_raw), "ip6tables -t raw -D PREROUTING %d", linenum -1); -#ifdef DEBUG - syslog(LOG_INFO, "Deleting ip6tables rule:"); - syslog(LOG_INFO, " -> %s", cmd); - syslog(LOG_INFO, " -> %s", cmd_raw); -#endif - // TODO Add a better checking error. - if(system(cmd) < 0 || system(cmd_raw) < 0) - { - return 0; - } - } - } - upnp_update_expiredpinhole(); - return r; + unsigned short uid_s; + + if(!uid) + return -1; + uid_s = (unsigned short)atoi(uid); +#ifdef USE_PF + return delete_pinhole(uid_s); #else -return -1; + return -1; #endif } diff --git a/miniupnpd/upnpsoap.c b/miniupnpd/upnpsoap.c index acb6921..7d4ccc6 100644 --- a/miniupnpd/upnpsoap.c +++ b/miniupnpd/upnpsoap.c @@ -1,4 +1,4 @@ -/* $Id: upnpsoap.c,v 1.93 2012/04/19 22:04:48 nanard Exp $ */ +/* $Id: upnpsoap.c,v 1.96 2012/04/20 14:38:39 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2012 Thomas Bernard @@ -1259,8 +1259,6 @@ static int PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short * int_port) { int n; - /* Pinhole InternalClient address must correspond to the action sender */ - syslog(LOG_INFO, "Checking internal IP@ and port (Security policy purpose)"); char senderAddr[INET6_ADDRSTRLEN]=""; #if 0 //char str[INET6_ADDRSTRLEN]=""; @@ -1271,6 +1269,9 @@ PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short * int_por struct addrinfo hints, *ai, *p; struct in6_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */ + /* Pinhole InternalClient address must correspond to the action sender */ + syslog(LOG_INFO, "Checking internal IP@ and port (Security policy purpose)"); + hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; @@ -1341,6 +1342,7 @@ AddPinhole(struct upnphttp * h, const char * action) char * rem_host, * rem_port, * int_ip, * int_port, * protocol, * leaseTime; int uid = 0; unsigned short iport, rport; + int ltime; if(CheckStatus(h)==0) return; @@ -1353,9 +1355,17 @@ AddPinhole(struct upnphttp * h, const char * action) protocol = GetValueFromNameValueList(&data, "Protocol"); leaseTime = GetValueFromNameValueList(&data, "LeaseTime"); - rport = (unsigned short)atoi(rem_port); - iport = (unsigned short)atoi(int_port); + rport = (unsigned short)(rem_port ? atoi(rem_port) : 0); + iport = (unsigned short)(int_port ? atoi(int_port) : 0); + ltime = atoi(leaseTime); + /* In particular, [IGD2] RECOMMENDS that unauthenticated and + * unauthorized control points are only allowed to invoke + * this action with: + * - InternalPort value greater than or equal to 1024, + * - InternalClient value equals to the control point's IP address. + * It is REQUIRED that InternalClient cannot be one of IPv6 + * addresses used by the gateway. */ /* ** As there is no security policy, InternalClient must be equal * to the CP's IP address. */ if(DataVerification(h, int_ip, &iport, protocol, leaseTime) == 0 @@ -1377,7 +1387,11 @@ AddPinhole(struct upnphttp * h, const char * action) syslog(LOG_INFO, "%s: (inbound) from [%s]:%hu to [%s]:%hu with protocol %s during %ssec", action, rem_host?rem_host:"anywhere", rport, int_ip, iport, protocol, leaseTime); - r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, protocol, leaseTime, &uid); + /* In cases where the RemoteHost, RemotePort, InternalPort, + * InternalClient and Protocol are the same than an existing pinhole, + * but LeaseTime is different, the device MUST extend the existing + * pinhole's lease time and return the UniqueID of the existing pinhole. */ + r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, protocol, ltime, &uid); switch(r) { @@ -1407,6 +1421,7 @@ UpdatePinhole(struct upnphttp * h, const char * action) const char * uid, * leaseTime; char iaddr[40], proto[6], lt[12]; unsigned short iport; + int ltime = -1; if(CheckStatus(h)==0) return; @@ -1414,8 +1429,10 @@ UpdatePinhole(struct upnphttp * h, const char * action) ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); uid = GetValueFromNameValueList(&data, "UniqueID"); leaseTime = GetValueFromNameValueList(&data, "NewLeaseTime"); + if(leaseTime) + ltime = atoi(leaseTime); - if(!uid || !leaseTime || !atoi(leaseTime) || atoi(leaseTime) > 86400) + if(!uid || ltime <= 0 || ltime > 86400) { ClearNameValueList(&data); SoapError(h, 402, "Invalid Args"); @@ -1455,11 +1472,6 @@ UpdatePinhole(struct upnphttp * h, const char * action) static void GetOutboundPinholeTimeout(struct upnphttp * h, const char * action) { - if (!ipv6fc_firewall_enabled) - { - SoapError(h, 702, "FirewallDisabed"); - return; - } int r; static const char resp[] = @@ -1475,6 +1487,12 @@ GetOutboundPinholeTimeout(struct upnphttp * h, const char * action) int opt=0, proto=0; unsigned short iport, rport; + if (!ipv6fc_firewall_enabled) + { + SoapError(h, 702, "FirewallDisabed"); + return; + } + ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); int_ip = GetValueFromNameValueList(&data, "InternalClient"); int_port = GetValueFromNameValueList(&data, "InternalPort"); @@ -1508,8 +1526,6 @@ GetOutboundPinholeTimeout(struct upnphttp * h, const char * action) static void DeletePinhole(struct upnphttp * h, const char * action) { - if(CheckStatus(h)==0) - return; int r, n; static const char resp[] = @@ -1522,10 +1538,13 @@ DeletePinhole(struct upnphttp * h, const char * action) char iaddr[40], proto[6], lt[12]; unsigned short iport; + if(CheckStatus(h)==0) + return; + ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); uid = GetValueFromNameValueList(&data, "UniqueID"); - if(!uid) + if(!uid || atoi(uid) < 0 || atoi(uid) > 65535) { ClearNameValueList(&data); SoapError(h, 402, "Invalid Args"); @@ -1548,7 +1567,7 @@ DeletePinhole(struct upnphttp * h, const char * action) r = upnp_delete_inboundpinhole(uid); - if(r <= 0) + if(r < 0) { syslog(LOG_INFO, "%s: (inbound) failed to remove pinhole with ID: %s", action, uid); if(r==-4) @@ -1567,8 +1586,6 @@ DeletePinhole(struct upnphttp * h, const char * action) static void CheckPinholeWorking(struct upnphttp * h, const char * action) { - if(CheckStatus(h)==0) - return; int r, d; static const char resp[] = @@ -1585,6 +1602,9 @@ CheckPinholeWorking(struct upnphttp * h, const char * action) unsigned short eport, iport; int isWorking = 0; + if(CheckStatus(h)==0) + return; + ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); uid = GetValueFromNameValueList(&data, "UniqueID"); @@ -1665,8 +1685,6 @@ CheckPinholeWorking(struct upnphttp * h, const char * action) static void GetPinholePackets(struct upnphttp * h, const char * action) { - if(CheckStatus(h)==0) - return; int r, n; static const char resp[] = @@ -1683,6 +1701,9 @@ GetPinholePackets(struct upnphttp * h, const char * action) unsigned short iport; int pinholePackets = 0; + if(CheckStatus(h)==0) + return; + ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); uid = GetValueFromNameValueList(&data, "UniqueID");