Diff for /embedaddon/miniupnpd/ipfw/ipfwrdr.c between versions 1.1 and 1.1.1.2

version 1.1, 2012/02/21 23:16:02 version 1.1.1.2, 2012/05/29 12:55:57
Line 1 Line 1
   /* $Id$ */
 /*  /*
  * MiniUPnP project   * MiniUPnP project
  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/   * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
  * (c) 2009 Jardel Weyrich   * (c) 2009 Jardel Weyrich
    * (c) 2011 Thomas Bernard
  * This software is subject to the conditions detailed   * This software is subject to the conditions detailed
  * in the LICENCE file provided within the distribution   * in the LICENCE file provided within the distribution
  */   */
   
   #include "../config.h"
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/file.h>  #include <sys/file.h>
Line 61  struct file; Line 65  struct file;
 #include <unistd.h>  #include <unistd.h>
 #include <netinet/ip_fw.h>  #include <netinet/ip_fw.h>
 #include "ipfwaux.h"  #include "ipfwaux.h"
   #include "ipfwrdr.h"
   
 #include "../config.h"  
 #include "../upnpglobalvars.h"  #include "../upnpglobalvars.h"
   
   /* init and shutdown functions */
   
 int init_redirect(void) {  int init_redirect(void) {
        ipfw_exec(IP_FW_INIT, NULL, 0);        return ipfw_exec(IP_FW_INIT, NULL, 0);
        return 0; 
 }  }
   
 void shutdown_redirect(void) {  void shutdown_redirect(void) {
         ipfw_exec(IP_FW_TERM, NULL, 0);          ipfw_exec(IP_FW_TERM, NULL, 0);
 }  }
   
   /* ipfw cannot store descriptions and timestamp for port mappings so we keep
    * our own list in memory */
   struct mapping_desc_time {
           struct mapping_desc_time * next;
           unsigned int timestamp;
           unsigned short eport;
           short proto;
           char desc[];
   };
   
   static struct mapping_desc_time * mappings_list = NULL;
   
   /* add an element to the port mappings descriptions & timestamp list */
   static void
   add_desc_time(unsigned short eport, int proto,
                 const char * desc, unsigned int timestamp)
   {
           struct mapping_desc_time * tmp;
           size_t l;
           if(!desc)
                   desc = "miniupnpd";
           l = strlen(desc) + 1;
           tmp = malloc(sizeof(struct mapping_desc_time) + l);
           if(tmp) {
                   /* fill the element and insert it as head of the list */
                   tmp->next = mappings_list;
                   tmp->timestamp = timestamp;
                   tmp->eport = eport;
                   tmp->proto = (short)proto;
                   memcpy(tmp->desc, desc, l);
                   mappings_list = tmp;
           }
   }
   
   /* remove an element to the port mappings descriptions & timestamp list */
   static void
   del_desc_time(unsigned short eport, int proto)
   {
           struct mapping_desc_time * e;
           struct mapping_desc_time * * p;
           p = &mappings_list;
           e = *p;
           while(e) {
                   if(e->eport == eport && e->proto == (short)proto) {
                           *p = e->next;
                           free(e);
                           return;
                   } else {
                           p = &e->next;
                           e = *p;
                   }
           }
   }
   
   /* go through the list and find the description and timestamp */
   static void
   get_desc_time(unsigned short eport, int proto,
                 char * desc, int desclen,
                 unsigned int * timestamp)
   {
           struct mapping_desc_time * e;
   
           for(e = mappings_list; e; e = e->next) {
                   if(e->eport == eport && e->proto == (short)proto) {
                           if(desc)
                                   strlcpy(desc, e->desc, desclen);
                           if(timestamp)
                                   *timestamp = e->timestamp;
                           return;
                   }
           }
   }
   
   /* --- */
 int add_redirect_rule2(  int add_redirect_rule2(
         const char * ifname,          const char * ifname,
           const char * rhost,
         unsigned short eport,          unsigned short eport,
         const char * iaddr,          const char * iaddr,
         unsigned short iport,          unsigned short iport,
         int proto,          int proto,
        const char * desc)        const char * desc,
         unsigned int timestamp)
 {  {
         struct ip_fw rule;          struct ip_fw rule;
           int r;
   
         if (ipfw_validate_protocol(proto) < 0)          if (ipfw_validate_protocol(proto) < 0)
                 return -1;                  return -1;
Line 93  int add_redirect_rule2( Line 174  int add_redirect_rule2(
         memset(&rule, 0, sizeof(struct ip_fw));          memset(&rule, 0, sizeof(struct ip_fw));
         rule.version = IP_FW_CURRENT_API_VERSION;          rule.version = IP_FW_CURRENT_API_VERSION;
         //rule.fw_number = 1000; // rule number          //rule.fw_number = 1000; // rule number
        rule.context = (void *)desc; // TODO keep this?        //rule.context = (void *)desc; // The description is kept in a separate list
         rule.fw_prot = proto; // protocol          rule.fw_prot = proto; // protocol
         rule.fw_flg |= IP_FW_F_IIFACE; // interfaces to check          rule.fw_flg |= IP_FW_F_IIFACE; // interfaces to check
         rule.fw_flg |= IP_FW_F_IIFNAME; // interfaces to check by name          rule.fw_flg |= IP_FW_F_IIFNAME; // interfaces to check by name
Line 101  int add_redirect_rule2( Line 182  int add_redirect_rule2(
         rule.fw_flg |= IP_FW_F_FWD; // forward action          rule.fw_flg |= IP_FW_F_FWD; // forward action
 #ifdef USE_IFNAME_IN_RULES  #ifdef USE_IFNAME_IN_RULES
         if (ifname != NULL) {          if (ifname != NULL) {
                strcpy(rule.fw_in_if.fu_via_if.name, ifname); // src interface                strlcpy(rule.fw_in_if.fu_via_if.name, ifname, IFNAMSIZ); // src interface
                 rule.fw_in_if.fu_via_if.unit = -1;                  rule.fw_in_if.fu_via_if.unit = -1;
         }          }
 #endif  #endif
Line 111  int add_redirect_rule2( Line 192  int add_redirect_rule2(
         }                 }       
         memcpy(&rule.fw_dst,  &rule.fw_out_if.fu_via_ip, sizeof(struct in_addr));          memcpy(&rule.fw_dst,  &rule.fw_out_if.fu_via_ip, sizeof(struct in_addr));
         memcpy(&rule.fw_fwd_ip.sin_addr, &rule.fw_out_if.fu_via_ip, sizeof(struct in_addr));          memcpy(&rule.fw_fwd_ip.sin_addr, &rule.fw_out_if.fu_via_ip, sizeof(struct in_addr));
        rule.fw_dmsk.s_addr = INADDR_BROADCAST;        rule.fw_dmsk.s_addr = INADDR_BROADCAST; //TODO check this
         IP_FW_SETNDSTP(&rule, 1); // number of external ports          IP_FW_SETNDSTP(&rule, 1); // number of external ports
         rule.fw_uar.fw_pts[0] = eport; // external port          rule.fw_uar.fw_pts[0] = eport; // external port
         rule.fw_fwd_ip.sin_port = iport; // internal port          rule.fw_fwd_ip.sin_port = iport; // internal port
           if (rhost && rhost[0] != '\0') {
                   inet_aton(rhost, &rule.fw_src);
                   rule.fw_smsk.s_addr = htonl(INADDR_NONE);
           }
   
        return ipfw_exec(IP_FW_ADD, &rule, sizeof(rule));        r = ipfw_exec(IP_FW_ADD, &rule, sizeof(rule));
         if(r >= 0)
                 add_desc_time(eport, proto, desc, timestamp);
         return r;
 }  }
   
 /* get_redirect_rule()  /* get_redirect_rule()
Line 131  int get_redirect_rule( Line 219  int get_redirect_rule(
         unsigned short * iport,          unsigned short * iport,
         char * desc,           char * desc, 
         int desclen,          int desclen,
           char * rhost,
           int rhostlen,
           unsigned int * timestamp,
         u_int64_t * packets,          u_int64_t * packets,
         u_int64_t * bytes)          u_int64_t * bytes)
 {  {
Line 141  int get_redirect_rule( Line 232  int get_redirect_rule(
                 return -1;                  return -1;
         if (ipfw_validate_ifname(ifname) < 0)          if (ipfw_validate_ifname(ifname) < 0)
                 return -1;                  return -1;
                if (timestamp)
                 *timestamp = 0;
 
         do {          do {
                 count_rules = ipfw_fetch_ruleset(&rules, &total_rules, 10);                  count_rules = ipfw_fetch_ruleset(&rules, &total_rules, 10);
                 if (count_rules < 0)                  if (count_rules < 0)
Line 157  int get_redirect_rule( Line 250  int get_redirect_rule(
                                 *bytes = ptr->fw_bcnt;                                  *bytes = ptr->fw_bcnt;
                         if (iport != NULL)                          if (iport != NULL)
                                 *iport = ptr->fw_fwd_ip.sin_port;                                  *iport = ptr->fw_fwd_ip.sin_port;
                         if (desc != NULL && desclen > 0)  
                                 strlcpy(desc, "", desclen); // TODO should we copy ptr->context?  
                         if (iaddr != NULL && iaddrlen > 0) {                          if (iaddr != NULL && iaddrlen > 0) {
                                if (inet_ntop(AF_INET, &ptr->fw_out_if.fu_via_ip, iaddr, iaddrlen) == NULL) {                                /* looks like fw_out_if.fu_via_ip is zero */
                                 //if (inet_ntop(AF_INET, &ptr->fw_out_if.fu_via_ip, iaddr, iaddrlen) == NULL) {
                                 if (inet_ntop(AF_INET, &ptr->fw_fwd_ip.sin_addr, iaddr, iaddrlen) == NULL) {
                                         syslog(LOG_ERR, "inet_ntop(): %m");                                          syslog(LOG_ERR, "inet_ntop(): %m");
                                         goto error;                                          goto error;
                                 }                                                         }                       
                         }                          }
                           if (rhost != NULL && rhostlen > 0) {
                                   if (ptr->fw_src.s_addr == 0)
                                           rhost[0] = '\0';
                                   else if (inet_ntop(AF_INET, &ptr->fw_src.s_addr, rhost, rhostlen) == NULL) {
                                           syslog(LOG_ERR, "inet_ntop(): %m");
                                           goto error;
                                   }                       
                           }
                         // And what if we found more than 1 matching rule?                          // And what if we found more than 1 matching rule?
                         ipfw_free_ruleset(&rules);                          ipfw_free_ruleset(&rules);
                           get_desc_time(eport, proto, desc, desclen, timestamp);
                         return 0;                          return 0;
                 }                  }
         }          }
Line 203  int delete_redirect_rule( Line 305  int delete_redirect_rule(
                                 goto error;                                  goto error;
                         // And what if we found more than 1 matching rule?                          // And what if we found more than 1 matching rule?
                         ipfw_free_ruleset(&rules);                          ipfw_free_ruleset(&rules);
                           del_desc_time(eport, proto);
                         return 0;                          return 0;
                 }                  }
         }          }
Line 215  error: Line 318  error:
   
 int add_filter_rule2(  int add_filter_rule2(
         const char * ifname,           const char * ifname, 
           const char * rhost,
         const char * iaddr,          const char * iaddr,
         unsigned short eport,           unsigned short eport, 
         unsigned short iport,          unsigned short iport,
         int proto,           int proto, 
         const char * desc)          const char * desc)
 {  {
        return -1;        //return -1;
         return 0; /* nothing to do, always success */
 }  }
   
 int delete_filter_rule(  int delete_filter_rule(
Line 229  int delete_filter_rule( Line 334  int delete_filter_rule(
         unsigned short eport,           unsigned short eport, 
         int proto)           int proto) 
 {  {
        return -1;        //return -1;
         return 0; /* nothing to do, always success */
 }  }
   
 int get_redirect_rule_by_index(  int get_redirect_rule_by_index(
Line 242  int get_redirect_rule_by_index( Line 348  int get_redirect_rule_by_index(
         int * proto,           int * proto, 
         char * desc,           char * desc, 
         int desclen,          int desclen,
           char * rhost,
           int rhostlen,
           unsigned int * timestamp,
         u_int64_t * packets,           u_int64_t * packets, 
         u_int64_t * bytes)          u_int64_t * bytes)
 {  {
Line 251  int get_redirect_rule_by_index( Line 360  int get_redirect_rule_by_index(
         if (index < 0) // TODO shouldn't we also validate the maximum?          if (index < 0) // TODO shouldn't we also validate the maximum?
                 return -1;                  return -1;
   
           if(timestamp)
                   *timestamp = 0;
   
         ipfw_fetch_ruleset(&rules, &total_rules, index + 1);          ipfw_fetch_ruleset(&rules, &total_rules, index + 1);
   
        if (total_rules == index + 1) {        if (total_rules > index) {
                 const struct ip_fw const * ptr = &rules[index];                  const struct ip_fw const * ptr = &rules[index];
                   if (ptr->fw_prot == 0)  // invalid rule
                           goto error;
                 if (proto != NULL)                  if (proto != NULL)
                         *proto = ptr->fw_prot;                          *proto = ptr->fw_prot;
                 if (eport != NULL)                  if (eport != NULL)
Line 269  int get_redirect_rule_by_index( Line 383  int get_redirect_rule_by_index(
                         *bytes = ptr->fw_bcnt;                          *bytes = ptr->fw_bcnt;
                 if (iport != NULL)                  if (iport != NULL)
                         *iport = ptr->fw_fwd_ip.sin_port;                          *iport = ptr->fw_fwd_ip.sin_port;
                 if (desc != NULL && desclen > 0)  
                         strlcpy(desc, "", desclen); // TODO should we copy ptr->context?  
                 if (iaddr != NULL && iaddrlen > 0) {                  if (iaddr != NULL && iaddrlen > 0) {
                        if (inet_ntop(AF_INET, &ptr->fw_out_if.fu_via_ip, iaddr, iaddrlen) == NULL) {                        /* looks like fw_out_if.fu_via_ip is zero */
                         //if (inet_ntop(AF_INET, &ptr->fw_out_if.fu_via_ip, iaddr, iaddrlen) == NULL) {
                         if (inet_ntop(AF_INET, &ptr->fw_fwd_ip.sin_addr, iaddr, iaddrlen) == NULL) {
                                 syslog(LOG_ERR, "inet_ntop(): %m");                                  syslog(LOG_ERR, "inet_ntop(): %m");
                                 goto error;                                  goto error;
                         }                                                 }                       
                 }                  }
                   if (rhost != NULL && rhostlen > 0) {
                           if (ptr->fw_src.s_addr == 0)
                                   rhost[0] = '\0';
                           else if (inet_ntop(AF_INET, &ptr->fw_src.s_addr, rhost, rhostlen) == NULL) {
                                   syslog(LOG_ERR, "inet_ntop(): %m");
                                   goto error;
                           }                       
                   }
                 ipfw_free_ruleset(&rules);                  ipfw_free_ruleset(&rules);
                   get_desc_time(*eport, *proto, desc, desclen, timestamp);
                 return 0;                  return 0;
         }          }
   
Line 286  error: Line 409  error:
                 ipfw_free_ruleset(&rules);                        ipfw_free_ruleset(&rules);      
         return -1;                return -1;      
 }  }
   
   /* upnp_get_portmappings_in_range()
    * return a list of all "external" ports for which a port
    * mapping exists */
   unsigned short *
   get_portmappings_in_range(unsigned short startport,
                             unsigned short endport,
                             int proto,
                             unsigned int * number)
   {
           unsigned short * array = NULL;
           unsigned int capacity = 128;
           int i, count_rules, total_rules = 0;
           struct ip_fw * rules = NULL;
           
           if (ipfw_validate_protocol(proto) < 0)
                   return NULL;
           
           do {
                   count_rules = ipfw_fetch_ruleset(&rules, &total_rules, 10);
                   if (count_rules < 0)
                           goto error;
           } while (count_rules == 10);
           
           array = calloc(capacity, sizeof(unsigned short));
           if(!array) {
                   syslog(LOG_ERR, "get_portmappings_in_range() : calloc error");
                   goto error;
           }
           *number = 0;
   
           for (i=0; i<total_rules-1; i++) {
                   const struct ip_fw const * ptr = &rules[i];
                   unsigned short eport = ptr->fw_uar.fw_pts[0];
                   if (proto == ptr->fw_prot
                       && startport <= eport
                       && eport <= endport) {
                           if(*number >= capacity) {
                                   capacity += 128;
                                   array = realloc(array, sizeof(unsigned short)*capacity);
                                   if(!array) {
                                           syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%lu) error", sizeof(unsigned short)*capacity);
                                           *number = 0;
                                           goto error;
                                   }
                           }
                           array[*number] = eport;
                           (*number)++;
                   }
           }
   error:
           if (rules != NULL)
                   ipfw_free_ruleset(&rules);      
           return array;
   }
   

Removed from v.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>