Diff for /embedaddon/miniupnpd/netfilter/iptcrdr.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$ */  /* $Id$ */
 /* MiniUPnP project  /* MiniUPnP project
  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/   * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
 * (c) 2006-2008 Thomas Bernard * (c) 2006-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 <stdio.h>  #include <stdio.h>
Line 20 Line 20
   
 #if IPTABLES_143  #if IPTABLES_143
 /* IPTABLES API version >= 1.4.3 */  /* IPTABLES API version >= 1.4.3 */
   
   /* added in order to compile on gentoo :
    * http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=2183 */
   #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
   #define __must_be_array(a) \
           BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))
   #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
   #define LIST_POISON2  ((void *) 0x00200200 )
   
 #include <net/netfilter/nf_nat.h>  #include <net/netfilter/nf_nat.h>
 #define ip_nat_multi_range      nf_nat_multi_range  #define ip_nat_multi_range      nf_nat_multi_range
 #define ip_nat_range            nf_nat_range  #define ip_nat_range            nf_nat_range
Line 34 Line 43
 #define IPTC_HANDLE             iptc_handle_t  #define IPTC_HANDLE             iptc_handle_t
 #endif  #endif
   
   /* IPT_ALIGN was renamed XT_ALIGN in iptables-1.4.11 */
   #ifndef IPT_ALIGN
   #define IPT_ALIGN XT_ALIGN
   #endif
   
 #include "iptcrdr.h"  #include "iptcrdr.h"
 #include "../upnpglobalvars.h"  #include "../upnpglobalvars.h"
   
   /* local functions declarations */
   static int
   addnatrule(int proto, unsigned short eport,
              const char * iaddr, unsigned short iport,
              const char * rhost);
   
   static int
   add_filter_rule(int proto, const char * rhost,
                   const char * iaddr, unsigned short iport);
   
 /* dummy init and shutdown functions */  /* dummy init and shutdown functions */
 int init_redirect(void)  int init_redirect(void)
 {  {
Line 60  static int snprintip(char * dst, size_t size, uint32_t Line 84  static int snprintip(char * dst, size_t size, uint32_t
  * own structure to store them */   * own structure to store them */
 struct rdr_desc {  struct rdr_desc {
         struct rdr_desc * next;          struct rdr_desc * next;
           unsigned int timestamp;
         unsigned short eport;          unsigned short eport;
         short proto;          short proto;
         char str[];          char str[];
Line 68  struct rdr_desc { Line 93  struct rdr_desc {
 /* pointer to the chained list where descriptions are stored */  /* pointer to the chained list where descriptions are stored */
 static struct rdr_desc * rdr_desc_list = 0;  static struct rdr_desc * rdr_desc_list = 0;
   
   /* add a description to the list of redirection descriptions */
 static void  static void
add_redirect_desc(unsigned short eport, int proto, const char * desc)add_redirect_desc(unsigned short eport, int proto,
                   const char * desc, unsigned int timestamp)
 {  {
         struct rdr_desc * p;          struct rdr_desc * p;
         size_t l;          size_t l;
/*      if(desc)        /* set a default description if none given */
        {*/        if(!desc)
                if ((l = strlen(desc) + 1) == 1) l = 5;                desc = "miniupnpd";
                p = malloc(sizeof(struct rdr_desc) + l);        l = strlen(desc) + 1;
                if(p)        p = malloc(sizeof(struct rdr_desc) + l);
                {        if(p)
                        p->next = rdr_desc_list;        {
                        p->eport = eport;                p->next = rdr_desc_list;
                        p->proto = (short)proto;                p->timestamp = timestamp;
                        if(desc) memcpy(p->str, desc, l); else memcpy(p->str, "upnp", 4);                p->eport = eport;
                        rdr_desc_list = p;                p->proto = (short)proto;
                }                memcpy(p->str, desc, l);
/*      }*/                rdr_desc_list = p;
         }
 }  }
   
   /* delete a description from the list */
 static void  static void
 del_redirect_desc(unsigned short eport, int proto)  del_redirect_desc(unsigned short eport, int proto)
 {  {
Line 110  del_redirect_desc(unsigned short eport, int proto) Line 139  del_redirect_desc(unsigned short eport, int proto)
         }          }
 }  }
   
   /* go through the list to find the description */
 static void  static void
 get_redirect_desc(unsigned short eport, int proto,  get_redirect_desc(unsigned short eport, int proto,
                  char * desc, int desclen)                  char * desc, int desclen,
                   unsigned int * timestamp)
 {  {
         struct rdr_desc * p;          struct rdr_desc * p;
         if(!desc || (desclen == 0))  
                 return;  
         for(p = rdr_desc_list; p; p = p->next)          for(p = rdr_desc_list; p; p = p->next)
         {          {
                 if(p->eport == eport && p->proto == (short)proto)                  if(p->eport == eport && p->proto == (short)proto)
                 {                  {
                        strncpy(desc, p->str, desclen);                        if(desc)
                                 strncpy(desc, p->str, desclen);
                         if(timestamp)
                                 *timestamp = p->timestamp;
                         return;                          return;
                 }                  }
         }          }
         /* if no description was found, return miniupnpd as default */          /* if no description was found, return miniupnpd as default */
        strncpy(desc, "miniupnpd", desclen);        if(desc)
                 strncpy(desc, "miniupnpd", desclen);
         if(timestamp)
                 *timestamp = 0;
 }  }
   
int#if USE_INDEX_FROM_DESC_LIST
 static int
 get_redirect_desc_by_index(int index, unsigned short * eport, int * proto,  get_redirect_desc_by_index(int index, unsigned short * eport, int * proto,
                  char * desc, int desclen)                  char * desc, int desclen, unsigned int * timestamp)
 {  {
         int i = 0;          int i = 0;
         struct rdr_desc * p;          struct rdr_desc * p;
Line 144  get_redirect_desc_by_index(int index, unsigned short * Line 180  get_redirect_desc_by_index(int index, unsigned short *
                         *eport = p->eport;                          *eport = p->eport;
                         *proto = (int)p->proto;                          *proto = (int)p->proto;
                         strncpy(desc, p->str, desclen);                          strncpy(desc, p->str, desclen);
                           if(timestamp)
                                   *timestamp = p->timestamp;
                         return 0;                          return 0;
                 }                  }
         }          }
         return -1;          return -1;
 }  }
   #endif
   
 /* add_redirect_rule2() */  /* add_redirect_rule2() */
 int  int
add_redirect_rule2(const char * ifname, unsigned short eport,add_redirect_rule2(const char * ifname,
                    const char * rhost, unsigned short eport,
                    const char * iaddr, unsigned short iport, int proto,                     const char * iaddr, unsigned short iport, int proto,
                                   const char * desc)                                   const char * desc, unsigned int timestamp)
 {  {
        int r = addnatrule(proto, eport, iaddr, iport);        int r = addnatrule(proto, eport, iaddr, iport, rhost);
         if(r >= 0)          if(r >= 0)
                add_redirect_desc(eport, proto, desc);                add_redirect_desc(eport, proto, desc, timestamp);
         return r;          return r;
 }  }
   
 int  int
add_filter_rule2(const char * ifname, const char * iaddr,add_filter_rule2(const char * ifname,
                  const char * rhost, const char * iaddr,
                  unsigned short eport, unsigned short iport,                   unsigned short eport, unsigned short iport,
                  int proto, const char * desc)                   int proto, const char * desc)
 {  {
        return add_filter_rule(proto, iaddr, iport);        return add_filter_rule(proto, rhost, iaddr, iport);
 }  }
   
 /* get_redirect_rule()   /* get_redirect_rule() 
Line 176  int Line 217  int
 get_redirect_rule(const char * ifname, unsigned short eport, int proto,  get_redirect_rule(const char * ifname, unsigned short eport, int proto,
                   char * iaddr, int iaddrlen, unsigned short * iport,                    char * iaddr, int iaddrlen, unsigned short * iport,
                   char * desc, int desclen,                    char * desc, int desclen,
                     char * rhost, int rhostlen,
                     unsigned int * timestamp,
                   u_int64_t * packets, u_int64_t * bytes)                    u_int64_t * packets, u_int64_t * bytes)
 {  {
         int r = -1;          int r = -1;
Line 231  get_redirect_rule(const char * ifname, unsigned short  Line 274  get_redirect_rule(const char * ifname, unsigned short 
                                 mr = (const struct ip_nat_multi_range *)&target->data[0];                                  mr = (const struct ip_nat_multi_range *)&target->data[0];
                                 snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip));                                  snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip));
                                 *iport = ntohs(mr->range[0].min.all);                                  *iport = ntohs(mr->range[0].min.all);
                                /*if(desc)                                get_redirect_desc(eport, proto, desc, desclen, timestamp);
                                        strncpy(desc, "miniupnpd", desclen);*/ 
                                get_redirect_desc(eport, proto, desc, desclen); 
                                 if(packets)                                  if(packets)
                                         *packets = e->counters.pcnt;                                          *packets = e->counters.pcnt;
                                 if(bytes)                                  if(bytes)
                                         *bytes = e->counters.bcnt;                                          *bytes = e->counters.bcnt;
                                   /* rhost */
                                   if(e->ip.src.s_addr && rhost) {
                                           snprintip(rhost, rhostlen, ntohl(e->ip.src.s_addr));
                                   }
                                 r = 0;                                  r = 0;
                                 break;                                  break;
                         }                          }
Line 259  get_redirect_rule_by_index(int index, Line 304  get_redirect_rule_by_index(int index,
                            char * ifname, unsigned short * eport,                             char * ifname, unsigned short * eport,
                            char * iaddr, int iaddrlen, unsigned short * iport,                             char * iaddr, int iaddrlen, unsigned short * iport,
                            int * proto, char * desc, int desclen,                             int * proto, char * desc, int desclen,
                              char * rhost, int rhostlen,
                              unsigned int * timestamp,
                            u_int64_t * packets, u_int64_t * bytes)                             u_int64_t * packets, u_int64_t * bytes)
 {  {
         int r = -1;          int r = -1;
        r = get_redirect_desc_by_index(index, eport, proto, desc, desclen);#if USE_INDEX_FROM_DESC_LIST
         r = get_redirect_desc_by_index(index, eport, proto,
                                        desc, desclen, timestamp);
         if (r==0)          if (r==0)
           {
                 r = get_redirect_rule(ifname, *eport, *proto, iaddr, iaddrlen, iport,                  r = get_redirect_rule(ifname, *eport, *proto, iaddr, iaddrlen, iport,
                                       0, 0, packets, bytes);                                        0, 0, packets, bytes);
#if 0        }
 #else
         int i = 0;          int i = 0;
         IPTC_HANDLE h;          IPTC_HANDLE h;
         const struct ipt_entry * e;          const struct ipt_entry * e;
Line 318  get_redirect_rule_by_index(int index, Line 369  get_redirect_rule_by_index(int index,
                                 mr = (const struct ip_nat_multi_range *)&target->data[0];                                  mr = (const struct ip_nat_multi_range *)&target->data[0];
                                 snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip));                                  snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip));
                                 *iport = ntohs(mr->range[0].min.all);                                  *iport = ntohs(mr->range[0].min.all);
                /*if(desc)                                get_redirect_desc(*eport, *proto, desc, desclen, timestamp);
                                    strncpy(desc, "miniupnpd", desclen);*/ 
                                get_redirect_desc(*eport, *proto, desc, desclen); 
                                 if(packets)                                  if(packets)
                                         *packets = e->counters.pcnt;                                          *packets = e->counters.pcnt;
                                 if(bytes)                                  if(bytes)
                                         *bytes = e->counters.bcnt;                                          *bytes = e->counters.bcnt;
                                   /* rhost */
                                   if(rhost && rhostlen > 0) {
                                           if(e->ip.src.s_addr) {
                                                   snprintip(rhost, rhostlen, ntohl(e->ip.src.s_addr));
                                           } else {
                                                   rhost[0] = '\0';
                                           }
                                   }
                                 r = 0;                                  r = 0;
                                 break;                                  break;
                         }                          }
Line 337  get_redirect_rule_by_index(int index, Line 394  get_redirect_rule_by_index(int index,
 #else  #else
                 iptc_free(&h);                  iptc_free(&h);
 #endif  #endif
#endif /*0*/#endif
         return r;          return r;
 }  }
   
 /* delete_rule_and_commit() :  /* delete_rule_and_commit() :
  * subfunction used in delete_redirect_and_filter_rules() */   * subfunction used in delete_redirect_and_filter_rules() */
   static int
   delete_rule_and_commit(unsigned int index, IPTC_HANDLE h,
                          const char * miniupnpd_chain,
                          const char * logcaller)
   {
           int r = 0;
   #ifdef IPTABLES_143
           if(!iptc_delete_num_entry(miniupnpd_chain, index, h))
   #else
           if(!iptc_delete_num_entry(miniupnpd_chain, index, &h))
   #endif
           {
                   syslog(LOG_ERR, "%s() : iptc_delete_num_entry(): %s\n",
                      logcaller, iptc_strerror(errno));
                   r = -1;
           }
   #ifdef IPTABLES_143
           else if(!iptc_commit(h))
   #else
           else if(!iptc_commit(&h))
   #endif
           {
                   syslog(LOG_ERR, "%s() : iptc_commit(): %s\n",
                      logcaller, iptc_strerror(errno));
                   r = -1;
           }
           if(h)
   #ifdef IPTABLES_143
                   iptc_free(h);
   #else
                   iptc_free(&h);
   #endif
           return r;
   }
   
   /* delete_redirect_and_filter_rules()
    */
 int  int
delete_rule_and_commit(const char * table,delete_redirect_and_filter_rules(unsigned short eport, int proto)
               const char * miniupnpd_chain, 
               unsigned short eport, int proto, 
               const char * logcaller) 
 {  {
         int r = -1;          int r = -1;
         unsigned index = 0;          unsigned index = 0;
         unsigned i = 0;          unsigned i = 0;
         IPTC_HANDLE h;          IPTC_HANDLE h;
         const struct ipt_entry * e;          const struct ipt_entry * e;
           const struct ipt_entry_target * target;
           const struct ip_nat_multi_range * mr;
         const struct ipt_entry_match *match;          const struct ipt_entry_match *match;
           unsigned short iport = 0;
           uint32_t iaddr = 0;
   
        h = iptc_init(table);        h = iptc_init("nat");
         if(!h)          if(!h)
         {          {
                syslog(LOG_ERR, "get_index_rules() : "                syslog(LOG_ERR, "delete_redirect_and_filter_rules() : "
                                "iptc_init(%s) failed : %s",                                "iptc_init() failed : %s",
                       table, 
                        iptc_strerror(errno));                         iptc_strerror(errno));
                 return -1;                  return -1;
         }          }
        if(!iptc_is_chain(miniupnpd_chain, h))        /* First step : find the right nat rule */
         if(!iptc_is_chain(miniupnpd_nat_chain, h))
         {          {
                syslog(LOG_ERR, "chain %s not found", miniupnpd_chain);                syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain);
         }          }
         else          else
         {          {
 #ifdef IPTABLES_143  #ifdef IPTABLES_143
                for(e = iptc_first_rule(miniupnpd_chain, h);                for(e = iptc_first_rule(miniupnpd_nat_chain, h);
                     e;                      e;
                         e = iptc_next_rule(e, h), i++)                          e = iptc_next_rule(e, h), i++)
 #else  #else
                for(e = iptc_first_rule(miniupnpd_chain, &h);                for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
                     e;                      e;
                         e = iptc_next_rule(e, &h), i++)                          e = iptc_next_rule(e, &h), i++)
 #endif  #endif
Line 398  delete_rule_and_commit(const char * table, Line 493  delete_rule_and_commit(const char * table,
                                         if(eport != info->dpts[0])                                          if(eport != info->dpts[0])
                                                 continue;                                                  continue;
                                 }                                  }
                                r = 0;                                /* get the index, the internal address and the internal port
                                  * of the rule */
                                 index = i;                                  index = i;
                                   target = (void *)e + e->target_offset;
                                   mr = (const struct ip_nat_multi_range *)&target->data[0];
                                   iaddr = mr->range[0].min_ip;
                                   iport = ntohs(mr->range[0].min.all);
                                   r = 0;
                                 break;                                  break;
                         }                          }
                 }                  }
Line 410  delete_rule_and_commit(const char * table, Line 511  delete_rule_and_commit(const char * table,
 #else  #else
                 iptc_free(&h);                  iptc_free(&h);
 #endif  #endif
        if ((r == 0) && (h = iptc_init(table))) {        if(r == 0)
                syslog(LOG_INFO, "Trying to delete rules at index %u", index);        {
                 syslog(LOG_INFO, "Trying to delete nat rule at index %u", index);
                 /* Now delete both rules */                  /* Now delete both rules */
                   /* first delete the nat rule */
                   h = iptc_init("nat");
                   if(h)
                   {
                           r = delete_rule_and_commit(index, h, miniupnpd_nat_chain, "delete_redirect_rule");
                   }
                   if((r == 0) && (h = iptc_init("filter")))
                   {
                           i = 0;
                           /* we must find the right index for the filter rule */
 #ifdef IPTABLES_143  #ifdef IPTABLES_143
        if(!iptc_delete_num_entry(miniupnpd_chain, index, h))                        for(e = iptc_first_rule(miniupnpd_forward_chain, h);
                             e;
                                 e = iptc_next_rule(e, h), i++)
 #else  #else
        if(!iptc_delete_num_entry(miniupnpd_chain, index, &h))                        for(e = iptc_first_rule(miniupnpd_forward_chain, &h);
                             e;
                                 e = iptc_next_rule(e, &h), i++)
 #endif  #endif
        {                        {
                syslog(LOG_ERR, "%s() : iptc_delete_num_entry(): %s\n",                                if(proto==e->ip.proto)
                   logcaller, iptc_strerror(errno));                                {
                r = -1;                                        match = (const struct ipt_entry_match *)&e->elems;
                                         /*syslog(LOG_DEBUG, "filter rule #%u: %s %s",
                                                i, match->u.user.name, inet_ntoa(e->ip.dst));*/
                                         if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
                                         {
                                                 const struct ipt_tcp * info;
                                                 info = (const struct ipt_tcp *)match->data;
                                                 if(iport != info->dpts[0])
                                                         continue;
                                         }
                                         else
                                         {
                                                 const struct ipt_udp * info;
                                                 info = (const struct ipt_udp *)match->data;
                                                 if(iport != info->dpts[0])
                                                         continue;
                                         }
                                         if(iaddr != e->ip.dst.s_addr)
                                                 continue;
                                         index = i;
                                         break;
                                 }
                         }
                         syslog(LOG_INFO, "Trying to delete filter rule at index %u", index);
                         r = delete_rule_and_commit(index, h, miniupnpd_forward_chain, "delete_filter_rule");
                 }
         }          }
#ifdef IPTABLES_143        del_redirect_desc(eport, proto);
        else if(!iptc_commit(h)) 
#else 
        else if(!iptc_commit(&h)) 
#endif 
        { 
                syslog(LOG_ERR, "%s() : iptc_commit(): %s\n", 
                   logcaller, iptc_strerror(errno)); 
                r = -1; 
        } 
        if(h) 
#ifdef IPTABLES_143 
                iptc_free(h); 
#else 
                iptc_free(&h); 
#endif 
        } 
         return r;          return r;
 }  }
   
 /* delete_redirect_and_filter_rules()  
  */  
 int  
 delete_redirect_and_filter_rules(unsigned short eport, int proto)  
 {  
         int r = -1;  
         if ((r = delete_rule_and_commit("nat", miniupnpd_nat_chain, eport, proto, "delete_redirect_rule") &&  
             delete_rule_and_commit("filter", miniupnpd_forward_chain, eport, proto, "delete_filter_rule")) == 0)  
                 del_redirect_desc(eport, proto);  
         return r;  
 }  
   
 /* ==================================== */  /* ==================================== */
 /* TODO : add the -m state --state NEW,ESTABLISHED,RELATED   /* TODO : add the -m state --state NEW,ESTABLISHED,RELATED 
  * only for the filter rule */   * only for the filter rule */
Line 468  get_tcp_match(unsigned short dport) Line 581  get_tcp_match(unsigned short dport)
                + IPT_ALIGN(sizeof(struct ipt_tcp));                 + IPT_ALIGN(sizeof(struct ipt_tcp));
         match = calloc(1, size);          match = calloc(1, size);
         match->u.match_size = size;          match->u.match_size = size;
        strncpy(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN);        strncpy(match->u.user.name, "tcp", sizeof(match->u.user.name));
         tcpinfo = (struct ipt_tcp *)match->data;          tcpinfo = (struct ipt_tcp *)match->data;
         tcpinfo->spts[0] = 0;           /* all source ports */          tcpinfo->spts[0] = 0;           /* all source ports */
         tcpinfo->spts[1] = 0xFFFF;          tcpinfo->spts[1] = 0xFFFF;
Line 487  get_udp_match(unsigned short dport) Line 600  get_udp_match(unsigned short dport)
                + IPT_ALIGN(sizeof(struct ipt_udp));                 + IPT_ALIGN(sizeof(struct ipt_udp));
         match = calloc(1, size);          match = calloc(1, size);
         match->u.match_size = size;          match->u.match_size = size;
        strncpy(match->u.user.name, "udp", IPT_FUNCTION_MAXNAMELEN);        strncpy(match->u.user.name, "udp", sizeof(match->u.user.name));
         udpinfo = (struct ipt_udp *)match->data;          udpinfo = (struct ipt_udp *)match->data;
         udpinfo->spts[0] = 0;           /* all source ports */          udpinfo->spts[0] = 0;           /* all source ports */
         udpinfo->spts[1] = 0xFFFF;          udpinfo->spts[1] = 0xFFFF;
Line 508  get_dnat_target(const char * daddr, unsigned short dpo Line 621  get_dnat_target(const char * daddr, unsigned short dpo
                + IPT_ALIGN(sizeof(struct ip_nat_multi_range));                 + IPT_ALIGN(sizeof(struct ip_nat_multi_range));
         target = calloc(1, size);          target = calloc(1, size);
         target->u.target_size = size;          target->u.target_size = size;
        strncpy(target->u.user.name, "DNAT", IPT_FUNCTION_MAXNAMELEN);        strncpy(target->u.user.name, "DNAT", sizeof(target->u.user.name));
         /* one ip_nat_range already included in ip_nat_multi_range */          /* one ip_nat_range already included in ip_nat_multi_range */
         mr = (struct ip_nat_multi_range *)&target->data[0];          mr = (struct ip_nat_multi_range *)&target->data[0];
         mr->rangesize = 1;          mr->rangesize = 1;
Line 523  get_dnat_target(const char * daddr, unsigned short dpo Line 636  get_dnat_target(const char * daddr, unsigned short dpo
 /* iptc_init_verify_and_append()  /* iptc_init_verify_and_append()
  * return 0 on success, -1 on failure */   * return 0 on success, -1 on failure */
 static int  static int
iptc_init_verify_and_append(const char * table, const char * miniupnpd_chain, struct ipt_entry * e,iptc_init_verify_and_append(const char * table,
                             const char * miniupnpd_chain,
                             struct ipt_entry * e,
                             const char * logcaller)                              const char * logcaller)
 {  {
         IPTC_HANDLE h;          IPTC_HANDLE h;
Line 536  iptc_init_verify_and_append(const char * table, const  Line 651  iptc_init_verify_and_append(const char * table, const 
         }          }
         if(!iptc_is_chain(miniupnpd_chain, h))          if(!iptc_is_chain(miniupnpd_chain, h))
         {          {
                syslog(LOG_ERR, "%s : iptc_is_chain() error : %s\n",                syslog(LOG_ERR, "%s : chain %s not found",
                       logcaller, iptc_strerror(errno));                       logcaller, miniupnpd_chain);
                 if(h)                  if(h)
 #ifdef IPTABLES_143  #ifdef IPTABLES_143
                         iptc_free(h);                          iptc_free(h);
Line 591  iptc_init_verify_and_append(const char * table, const  Line 706  iptc_init_verify_and_append(const char * table, const 
 /* add nat rule   /* add nat rule 
  * iptables -t nat -A MINIUPNPD -p proto --dport eport -j DNAT --to iaddr:iport   * iptables -t nat -A MINIUPNPD -p proto --dport eport -j DNAT --to iaddr:iport
  * */   * */
intstatic int
 addnatrule(int proto, unsigned short eport,  addnatrule(int proto, unsigned short eport,
           const char * iaddr, unsigned short iport)           const char * iaddr, unsigned short iport,
            const char * rhost)
 {  {
         int r = 0;          int r = 0;
         struct ipt_entry * e;          struct ipt_entry * e;
Line 623  addnatrule(int proto, unsigned short eport, Line 739  addnatrule(int proto, unsigned short eport,
         e->next_offset = sizeof(struct ipt_entry)          e->next_offset = sizeof(struct ipt_entry)
                          + match->u.match_size                           + match->u.match_size
                                          + target->u.target_size;                                           + target->u.target_size;
           /* remote host */
           if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*")))
           {
                   e->ip.src.s_addr = inet_addr(rhost);
                   e->ip.smsk.s_addr = INADDR_NONE;
           }
                   
         r = iptc_init_verify_and_append("nat", miniupnpd_nat_chain, e, "addnatrule()");          r = iptc_init_verify_and_append("nat", miniupnpd_nat_chain, e, "addnatrule()");
         free(target);          free(target);
Line 640  get_accept_target(void) Line 762  get_accept_target(void)
                + IPT_ALIGN(sizeof(int));                 + IPT_ALIGN(sizeof(int));
         target = calloc(1, size);          target = calloc(1, size);
         target->u.user.target_size = size;          target->u.user.target_size = size;
        strncpy(target->u.user.name, "ACCEPT", IPT_FUNCTION_MAXNAMELEN);        strncpy(target->u.user.name, "ACCEPT", sizeof(target->u.user.name));
         return target;          return target;
 }  }
   
 /* add_filter_rule()  /* add_filter_rule()
  * */   * */
intstatic int
add_filter_rule(int proto, const char * iaddr, unsigned short iport)add_filter_rule(int proto, const char * rhost,
                 const char * iaddr, unsigned short iport)
 {  {
         int r = 0;          int r = 0;
         struct ipt_entry * e;          struct ipt_entry * e;
Line 679  add_filter_rule(int proto, const char * iaddr, unsigne Line 802  add_filter_rule(int proto, const char * iaddr, unsigne
         e->next_offset = sizeof(struct ipt_entry)          e->next_offset = sizeof(struct ipt_entry)
                          + match->u.match_size                           + match->u.match_size
                                          + target->u.target_size;                                           + target->u.target_size;
           /* remote host */
           if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*")))
           {
                   e->ip.src.s_addr = inet_addr(rhost);
                   e->ip.smsk.s_addr = INADDR_NONE;
           }
                   
         r = iptc_init_verify_and_append("filter", miniupnpd_forward_chain, e, "add_filter_rule()");          r = iptc_init_verify_and_append("filter", miniupnpd_forward_chain, e, "add_filter_rule()");
         free(target);          free(target);
Line 687  add_filter_rule(int proto, const char * iaddr, unsigne Line 816  add_filter_rule(int proto, const char * iaddr, unsigne
         return r;          return r;
 }  }
   
   /* return an (malloc'ed) array of "external" port for which there is
    * a port mapping. number is the size of the array */
   unsigned short *
   get_portmappings_in_range(unsigned short startport, unsigned short endport,
                             int proto, unsigned int * number)
   {
           unsigned short * array;
           unsigned int capacity;
           unsigned short eport;
           IPTC_HANDLE h;
           const struct ipt_entry * e;
           const struct ipt_entry_match *match;
   
           *number = 0;
           capacity = 128;
           array = calloc(capacity, sizeof(unsigned short));
           if(!array)
           {
                   syslog(LOG_ERR, "get_portmappings_in_range() : calloc error");
                   return NULL;
           }
   
           h = iptc_init("nat");
           if(!h)
           {
                   syslog(LOG_ERR, "get_redirect_rule_by_index() : "
                                   "iptc_init() failed : %s",
                          iptc_strerror(errno));
                   free(array);
                   return NULL;
           }
           if(!iptc_is_chain(miniupnpd_nat_chain, h))
           {
                   syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain);
                   free(array);
                   array = NULL;
           }
           else
           {
   #ifdef IPTABLES_143
                   for(e = iptc_first_rule(miniupnpd_nat_chain, h);
                       e;
                           e = iptc_next_rule(e, h))
   #else
                   for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
                       e;
                           e = iptc_next_rule(e, &h))
   #endif
                   {
                           if(proto == e->ip.proto)
                           {
                                   match = (const struct ipt_entry_match *)&e->elems;
                                   if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
                                   {
                                           const struct ipt_tcp * info;
                                           info = (const struct ipt_tcp *)match->data;
                                           eport = info->dpts[0];
                                   }
                                   else
                                   {
                                           const struct ipt_udp * info;
                                           info = (const struct ipt_udp *)match->data;
                                           eport = info->dpts[0];
                                   }
                                   if(startport <= eport && eport <= endport)
                                   {
                                           if(*number >= capacity)
                                           {
                                                   /* need to increase the capacity of the array */
                                                   array = realloc(array, sizeof(unsigned short)*capacity);
                                                   if(!array)
                                                   {
                                                           syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%u) error",
                                                                  (unsigned)sizeof(unsigned short)*capacity);
                                                           *number = 0;
                                                           break;
                                                   }
                                                   array[*number] = eport;
                                                   (*number)++;
                                           }
                                   }
                           }
                   }
           }
           if(h)
   #ifdef IPTABLES_143
                   iptc_free(h);
   #else
                   iptc_free(&h);
   #endif
           return array;
   }
   
 /* ================================ */  /* ================================ */
   #ifdef DEBUG
 static int  static int
 print_match(const struct ipt_entry_match *match)  print_match(const struct ipt_entry_match *match)
 {  {
Line 752  list_redirect_rule(const char * ifname) Line 975  list_redirect_rule(const char * ifname)
         const struct ipt_entry_target * target;          const struct ipt_entry_target * target;
         const struct ip_nat_multi_range * mr;          const struct ip_nat_multi_range * mr;
         const char * target_str;          const char * target_str;
           char addr[16], mask[16];
   
         h = iptc_init("nat");          h = iptc_init("nat");
         if(!h)          if(!h)
Line 783  list_redirect_rule(const char * ifname) Line 1007  list_redirect_rule(const char * ifname)
                 target_str = iptc_get_target(e, &h);                  target_str = iptc_get_target(e, &h);
 #endif  #endif
                 printf("===\n");                  printf("===\n");
                   inet_ntop(AF_INET, &e->ip.src, addr, sizeof(addr));
                   inet_ntop(AF_INET, &e->ip.smsk, mask, sizeof(mask));
                 printf("src = %s%s/%s\n", (e->ip.invflags & IPT_INV_SRCIP)?"! ":"",                  printf("src = %s%s/%s\n", (e->ip.invflags & IPT_INV_SRCIP)?"! ":"",
                       inet_ntoa(e->ip.src), inet_ntoa(e->ip.smsk));                       /*inet_ntoa(e->ip.src), inet_ntoa(e->ip.smsk)*/
                        addr, mask);
                 inet_ntop(AF_INET, &e->ip.dst, addr, sizeof(addr));
                 inet_ntop(AF_INET, &e->ip.dmsk, mask, sizeof(mask));
                 printf("dst = %s%s/%s\n", (e->ip.invflags & IPT_INV_DSTIP)?"! ":"",                  printf("dst = %s%s/%s\n", (e->ip.invflags & IPT_INV_DSTIP)?"! ":"",
                       inet_ntoa(e->ip.dst), inet_ntoa(e->ip.dmsk));                       /*inet_ntoa(e->ip.dst), inet_ntoa(e->ip.dmsk)*/
                        addr, mask);
                 /*printf("in_if = %s  out_if = %s\n", e->ip.iniface, e->ip.outiface);*/                  /*printf("in_if = %s  out_if = %s\n", e->ip.iniface, e->ip.outiface);*/
                 printf("in_if = ");                  printf("in_if = ");
                 print_iface(e->ip.iniface, e->ip.iniface_mask,                  print_iface(e->ip.iniface, e->ip.iniface_mask,
Line 822  list_redirect_rule(const char * ifname) Line 1052  list_redirect_rule(const char * ifname)
 #endif  #endif
         return 0;          return 0;
 }  }
#endif

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


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