root/net/ipv4/ip_fw.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. port_match
  2. ip_fw_chk
  3. masq_expire
  4. alloc_masq_entry
  5. revamp
  6. recalc_check
  7. ip_fw_masquerade
  8. ip_fw_demasquerade
  9. zero_fw_chain
  10. free_fw_chain
  11. add_to_chain
  12. del_from_chain
  13. check_ipfw_struct
  14. ip_acct_cnt
  15. ip_acct_ctl
  16. ip_fw_ctl
  17. ip_chain_procinfo
  18. ip_acct_procinfo
  19. ip_fw_blk_procinfo
  20. ip_fw_fwd_procinfo
  21. ip_msqhst_procinfo
  22. ipfw_input_check
  23. ipfw_forward_check
  24. ip_fw_init

   1 /*
   2  *      IP firewalling code. This is taken from 4.4BSD. Please note the 
   3  *      copyright message below. As per the GPL it must be maintained
   4  *      and the licenses thus do not conflict. While this port is subject
   5  *      to the GPL I also place my modifications under the original 
   6  *      license in recognition of the original copyright. 
   7  *                              -- Alan Cox.
   8  *
   9  *      Ported from BSD to Linux,
  10  *              Alan Cox 22/Nov/1994.
  11  *      Zeroing /proc and other additions
  12  *              Jos Vos 4/Feb/1995.
  13  *      Merged and included the FreeBSD-Current changes at Ugen's request
  14  *      (but hey it's a lot cleaner now). Ugen would prefer in some ways
  15  *      we waited for his final product but since Linux 1.2.0 is about to
  16  *      appear it's not practical - Read: It works, it's not clean but please
  17  *      don't consider it to be his standard of finished work.
  18  *              Alan Cox 12/Feb/1995
  19  *      Porting bidirectional entries from BSD, fixing accounting issues,
  20  *      adding struct ip_fwpkt for checking packets with interface address
  21  *              Jos Vos 5/Mar/1995.
  22  *      Established connections (ACK check), ACK check on bidirectional rules,
  23  *      ICMP type check.
  24  *              Wilfred Mollenvanger 7/7/1995.
  25  *      TCP attack protection.
  26  *              Alan Cox 25/8/95, based on information from bugtraq.
  27  *      ICMP type printk, IP_FW_F_APPEND
  28  *              Bernd Eckenfels 1996-01-31
  29  *
  30  * Masquerading functionality
  31  *
  32  * Copyright (c) 1994 Pauline Middelink
  33  *
  34  * The pieces which added masquerading functionality are totaly
  35  * my responsibility and have nothing to with the original authors
  36  * copyright or doing.
  37  *
  38  * Parts distributed under GPL.
  39  *
  40  * Fixes:
  41  *      Pauline Middelink       :       Added masquerading.
  42  *      Alan Cox                :       Fixed an error in the merge.
  43  *      Thomas Quinot           :       Fixed port spoofing.
  44  *      Alan Cox                :       Cleaned up retransmits in spoofing.
  45  *      Alan Cox                :       Cleaned up length setting.
  46  *      Wouter Gadeyne          :       Fixed masquerading support of ftp PORT commands
  47  *
  48  *      All the real work was done by .....
  49  *
  50  */
  51 
  52 
  53 /*
  54  * Copyright (c) 1993 Daniel Boulet
  55  * Copyright (c) 1994 Ugen J.S.Antsilevich
  56  *
  57  * Redistribution and use in source forms, with and without modification,
  58  * are permitted provided that this entire comment appears intact.
  59  *
  60  * Redistribution in binary form may occur without any restrictions.
  61  * Obviously, it would be nice if you gave credit where credit is due
  62  * but requiring it would be too onerous.
  63  *
  64  * This software is provided ``AS IS'' without any warranties of any kind.
  65  */
  66 
  67 #include <linux/config.h>
  68 #include <asm/segment.h>
  69 #include <asm/system.h>
  70 #include <linux/types.h>
  71 #include <linux/kernel.h>
  72 #include <linux/sched.h>
  73 #include <linux/string.h>
  74 #include <linux/errno.h>
  75 #include <linux/config.h>
  76 
  77 #include <linux/socket.h>
  78 #include <linux/sockios.h>
  79 #include <linux/in.h>
  80 #include <linux/inet.h>
  81 #include <linux/netdevice.h>
  82 #include <linux/icmp.h>
  83 #include <linux/udp.h>
  84 #include <net/ip.h>
  85 #include <net/protocol.h>
  86 #include <net/route.h>
  87 #include <net/tcp.h>
  88 #include <net/udp.h>
  89 #include <linux/skbuff.h>
  90 #include <net/sock.h>
  91 #include <net/icmp.h>
  92 #include <linux/firewall.h>
  93 #include <linux/ip_fw.h>
  94 #include <net/checksum.h>
  95 #include <linux/proc_fs.h>
  96 #include <linux/stat.h>
  97 
  98 /*
  99  *      Implement IP packet firewall
 100  */
 101 
 102 #ifdef CONFIG_IPFIREWALL_DEBUG 
 103 #define dprintf1(a)             printk(a)
 104 #define dprintf2(a1,a2)         printk(a1,a2)
 105 #define dprintf3(a1,a2,a3)      printk(a1,a2,a3)
 106 #define dprintf4(a1,a2,a3,a4)   printk(a1,a2,a3,a4)
 107 #else
 108 #define dprintf1(a)     
 109 #define dprintf2(a1,a2)
 110 #define dprintf3(a1,a2,a3)
 111 #define dprintf4(a1,a2,a3,a4)
 112 #endif
 113 
 114 #define print_ip(a)      printk("%ld.%ld.%ld.%ld",(ntohl(a)>>24)&0xFF,\
 115                                               (ntohl(a)>>16)&0xFF,\
 116                                               (ntohl(a)>>8)&0xFF,\
 117                                               (ntohl(a))&0xFF);
 118 
 119 #ifdef IPFIREWALL_DEBUG
 120 #define dprint_ip(a)    print_ip(a)
 121 #else
 122 #define dprint_ip(a)    
 123 #endif
 124 
 125 #ifdef CONFIG_IP_FIREWALL
 126 struct ip_fw *ip_fw_fwd_chain;
 127 struct ip_fw *ip_fw_blk_chain;
 128 int ip_fw_blk_policy=IP_FW_F_ACCEPT;
 129 int ip_fw_fwd_policy=IP_FW_F_ACCEPT;
 130 #endif
 131 #ifdef CONFIG_IP_ACCT
 132 struct ip_fw *ip_acct_chain;
 133 #endif
 134 
 135 #define IP_INFO_BLK     0
 136 #define IP_INFO_FWD     1
 137 #define IP_INFO_ACCT    2
 138 
 139 #ifdef CONFIG_IP_MASQUERADE
 140 /*
 141  *      Implement IP packet masquerading
 142  */
 143 
 144 static unsigned short masq_port = PORT_MASQ_BEGIN;
 145 static const char *strProt[] = {"UDP","TCP"};
 146 struct ip_masq *ip_msq_hosts;
 147 
 148 #endif
 149 
 150 /*
 151  *      Returns 1 if the port is matched by the vector, 0 otherwise
 152  */
 153 
 154 extern inline int port_match(unsigned short *portptr,int nports,unsigned short port,int range_flag)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156         if (!nports)
 157                 return 1;
 158         if ( range_flag ) 
 159         {
 160                 if ( portptr[0] <= port && port <= portptr[1] ) 
 161                 {
 162                         return( 1 );
 163                 }
 164                 nports -= 2;
 165                 portptr += 2;
 166         }
 167         while ( nports-- > 0 ) 
 168         {
 169                 if ( *portptr++ == port ) 
 170                 {
 171                         return( 1 );
 172                 }
 173         }
 174         return(0);
 175 }
 176 
 177 #if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
 178 
 179 
 180 /*
 181  *      Returns 0 if packet should be dropped, 1 if it should be accepted,
 182  *      and -1 if an ICMP host unreachable packet should be sent.
 183  *      Also does accounting so you can feed it the accounting chain.
 184  *      If opt is set to 1, it means that we do this for accounting
 185  *      purposes (searches all entries and handles fragments different).
 186  *      If opt is set to 2, it doesn't count a matching packet, which
 187  *      is used when calling this for checking purposes (IP_FW_CHK_*).
 188  */
 189 
 190 
 191 int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int policy, int opt)
     /* [previous][next][first][last][top][bottom][index][help] */
 192 {
 193         struct ip_fw *f;
 194         struct tcphdr           *tcp=(struct tcphdr *)((unsigned long *)ip+ip->ihl);
 195         struct udphdr           *udp=(struct udphdr *)((unsigned long *)ip+ip->ihl);
 196         struct icmphdr          *icmp=(struct icmphdr *)((unsigned long *)ip+ip->ihl);
 197         __u32                   src, dst;
 198         __u16                   src_port=0, dst_port=0, icmp_type=0;
 199         unsigned short          f_prt=0, prt;
 200         char                    notcpsyn=1, notcpack=1, match;
 201         unsigned short          offset;
 202         int                     answer, priority;
 203 
 204         /*
 205          *      If the chain is empty follow policy. The BSD one
 206          *      accepts anything giving you a time window while
 207          *      flushing and rebuilding the tables.
 208          */
 209          
 210         src = ip->saddr;
 211         dst = ip->daddr;
 212 
 213         /* 
 214          *      This way we handle fragmented packets.
 215          *      we ignore all fragments but the first one
 216          *      so the whole packet can't be reassembled.
 217          *      This way we relay on the full info which
 218          *      stored only in first packet.
 219          *
 220          *      Note that this theoretically allows partial packet
 221          *      spoofing. Not very dangerous but paranoid people may
 222          *      wish to play with this. It also allows the so called
 223          *      "fragment bomb" denial of service attack on some types
 224          *      of system.
 225          */
 226 
 227         offset = ntohs(ip->frag_off) & IP_OFFSET;
 228         
 229         /*
 230          *      Don't allow a fragment of TCP 8 bytes in. Nobody
 231          *      normal causes this. Its a cracker trying to break
 232          *      in by doing a flag overwrite to pass the direction
 233          *      checks.
 234          */
 235          
 236         if (offset == 1 && ip->protocol == IPPROTO_TCP)
 237                 return FW_BLOCK;
 238                 
 239         if (offset!=0 && (opt != 1) && (ip->protocol == IPPROTO_TCP ||
 240                         ip->protocol == IPPROTO_UDP))
 241                 return FW_ACCEPT;
 242                 
 243         /*
 244          *       Header fragment for TCP is too small to check the bits.
 245          */
 246          
 247         if(ip->protocol==IPPROTO_TCP && (ip->ihl<<2)+16 > ntohs(ip->tot_len))
 248                 return FW_BLOCK;
 249         
 250         /*
 251          *      Too short.
 252          */
 253          
 254         else if(ntohs(ip->tot_len)<8+(ip->ihl<<2))
 255                 return FW_BLOCK;
 256                 
 257         src = ip->saddr;
 258         dst = ip->daddr;
 259 
 260         /*
 261          *      If we got interface from which packet came
 262          *      we can use the address directly. This is unlike
 263          *      4.4BSD derived systems that have an address chain
 264          *      per device. We have a device per address with dummy
 265          *      devices instead.
 266          */
 267          
 268         dprintf1("Packet ");
 269         switch(ip->protocol) 
 270         {
 271                 case IPPROTO_TCP:
 272                         dprintf1("TCP ");
 273                         /* ports stay 0 if it is not the first fragment */
 274                         if (!offset) {
 275                                 src_port=ntohs(tcp->source);
 276                                 dst_port=ntohs(tcp->dest);
 277                                 if(tcp->ack)
 278                                         /* We *DO* have ACK, value FALSE */
 279                                         notcpack=0;
 280                                 if(tcp->syn && notcpack)
 281                                         /* We *DO* have SYN, value FALSE */
 282                                         notcpsyn=0;
 283                         }
 284                         prt=IP_FW_F_TCP;
 285                         break;
 286                 case IPPROTO_UDP:
 287                         dprintf1("UDP ");
 288                         /* ports stay 0 if it is not the first fragment */
 289                         if (!offset) {
 290                                 src_port=ntohs(udp->source);
 291                                 dst_port=ntohs(udp->dest);
 292                         }
 293                         prt=IP_FW_F_UDP;
 294                         break;
 295                 case IPPROTO_ICMP:
 296                         icmp_type=(__u16)(icmp->type);
 297                         dprintf2("ICMP:%d ",icmp_type);
 298                         prt=IP_FW_F_ICMP;
 299                         break;
 300                 default:
 301                         dprintf2("p=%d ",ip->protocol);
 302                         prt=IP_FW_F_ALL;
 303                         break;
 304         }
 305 #ifdef CONFIG_IP_FIREWALL_DEBUG
 306         dprint_ip(ip->saddr);
 307         
 308         if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
 309                 /* This will print 0 when it is not the first fragment! */
 310                 dprintf2(":%d ", src_port);
 311         dprint_ip(ip->daddr);
 312         if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
 313                 /* This will print 0 when it is not the first fragment! */
 314                 dprintf2(":%d ",dst_port);
 315         dprintf1("\n");
 316 #endif  
 317 
 318         for (f=chain;f;f=f->fw_next) 
 319         {
 320                 /*
 321                  *      This is a bit simpler as we don't have to walk
 322                  *      an interface chain as you do in BSD - same logic
 323                  *      however.
 324                  */
 325 
 326                 /*
 327                  *      Match can become 0x01 (a "normal" match was found),
 328                  *      0x02 (a reverse match was found), and 0x03 (the
 329                  *      IP addresses match in both directions).
 330                  *      Now we know in which direction(s) we should look
 331                  *      for a match for the TCP/UDP ports.  Both directions
 332                  *      might match (e.g., when both addresses are on the
 333                  *      same network for which an address/mask is given), but
 334                  *      the ports might only match in one direction.
 335                  *      This was obviously wrong in the original BSD code.
 336                  */
 337                 match = 0x00;
 338 
 339                 if ((src&f->fw_smsk.s_addr)==f->fw_src.s_addr
 340                 &&  (dst&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
 341                         /* normal direction */
 342                         match |= 0x01;
 343 
 344                 if ((f->fw_flg & IP_FW_F_BIDIR) &&
 345                     (dst&f->fw_smsk.s_addr)==f->fw_src.s_addr
 346                 &&  (src&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
 347                         /* reverse direction */
 348                         match |= 0x02;
 349 
 350                 if (match)
 351                 {
 352                         /*
 353                          *      Look for a VIA match 
 354                          */
 355                         if(f->fw_via.s_addr && rif)
 356                         {
 357                                 if(rif->pa_addr!=f->fw_via.s_addr)
 358                                         continue;       /* Mismatch */
 359                         }
 360                         /*
 361                          *      Drop through - this is a match
 362                          */
 363                 }
 364                 else
 365                         continue;
 366 
 367                 /*
 368                  *      Ok the chain addresses match.
 369                  */
 370 
 371                 f_prt=f->fw_flg&IP_FW_F_KIND;
 372                 if (f_prt!=IP_FW_F_ALL) 
 373                 {
 374                         /*
 375                          * This is actually buggy as if you set SYN flag 
 376                          * on UDP or ICMP firewall it will never work,but 
 377                          * actually it is a concern of software which sets
 378                          * firewall entries.
 379                          */
 380                          
 381                          if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn)
 382                                 continue;
 383 
 384                         /*
 385                          * When a bidirectional rule is used we only check
 386                          * for ack bits on reverse matches. This way it's
 387                          * easy to set up rules which only allow connections
 388                          * initiated from "normal" match adresses.
 389                          */
 390 
 391                         if((f->fw_flg&IP_FW_F_TCPACK) && notcpack)
 392                                 if(f->fw_flg&IP_FW_F_BIDIR) {
 393                                         if(match & 0x02)
 394                                                 continue;
 395                                 } else
 396                                         continue;
 397 
 398                         /*
 399                          *      Specific firewall - packet's protocol
 400                          *      must match firewall's.
 401                          */
 402 
 403                         if(prt!=f_prt)
 404                                 continue;
 405                                 
 406                         if((prt==IP_FW_F_ICMP &&
 407                                 ! port_match(&f->fw_pts[0], f->fw_nsp,
 408                                         icmp_type,f->fw_flg&IP_FW_F_SRNG)) ||
 409                             !(prt==IP_FW_F_ICMP || ((match & 0x01) &&
 410                                 port_match(&f->fw_pts[0], f->fw_nsp, src_port,
 411                                         f->fw_flg&IP_FW_F_SRNG) &&
 412                                 port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port,
 413                                         f->fw_flg&IP_FW_F_DRNG)) || ((match & 0x02) &&
 414                                 port_match(&f->fw_pts[0], f->fw_nsp, dst_port,
 415                                         f->fw_flg&IP_FW_F_SRNG) &&
 416                                 port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, src_port,
 417                                         f->fw_flg&IP_FW_F_DRNG))))
 418                         {
 419                                 continue;
 420                         }
 421                 }
 422 #ifdef CONFIG_IP_FIREWALL_VERBOSE
 423                 /*
 424                  * VERY ugly piece of code which actually
 425                  * makes kernel printf for denied packets...
 426                  */
 427 
 428                 if (f->fw_flg & IP_FW_F_PRN)
 429                 {
 430                         if(opt != 1) {
 431                                 if(f->fw_flg&IP_FW_F_ACCEPT)
 432                                         printk("Accept ");
 433                                 else if(f->fw_flg&IP_FW_F_ICMPRPL)
 434                                         printk("Reject ");
 435                                 else
 436                                         printk("Deny ");
 437                         }
 438                         switch(ip->protocol)
 439                         {
 440                                 case IPPROTO_TCP:
 441                                         printk("TCP ");
 442                                         break;
 443                                 case IPPROTO_UDP:
 444                                         printk("UDP ");
 445                                 case IPPROTO_ICMP:
 446                                         printk("ICMP:%d ",icmp_type);
 447                                         break;
 448                                 default:
 449                                         printk("p=%d ",ip->protocol);
 450                                         break;
 451                         }
 452                         print_ip(ip->saddr);
 453                         if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
 454                                 printk(":%d", src_port);
 455                         printk(" ");
 456                         print_ip(ip->daddr);
 457                         if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
 458                                 printk(":%d",dst_port);
 459                         printk("\n");
 460                 }
 461 #endif          
 462                 if (opt != 2) {
 463                         f->fw_bcnt+=ntohs(ip->tot_len);
 464                         f->fw_pcnt++;
 465                 }
 466                 if (opt != 1)
 467                         break;
 468         } /* Loop */
 469         
 470         answer = FW_BLOCK;
 471         
 472         /*
 473          * We rely on policy defined in the rejecting entry or, if no match
 474          * was found, we rely on the general policy variable for this type
 475          * of firewall.
 476          */
 477 
 478         if(f!=NULL) 
 479         {
 480                 policy=f->fw_flg;
 481                 priority=f->fw_priority;
 482         }
 483         else
 484                 priority=0xFF00;
 485 
 486         if(opt != 1) 
 487         {
 488                 if(policy&IP_FW_F_ACCEPT)
 489                         answer=(policy&IP_FW_F_MASQ)?FW_MASQUERADE:FW_ACCEPT;
 490                 else
 491                         if(policy&IP_FW_F_ICMPRPL)
 492                                 answer = FW_REJECT;
 493         }
 494 
 495         if (answer == 0) { /* Adjust priority and recompute checksum */
 496                 __u8 old_tos = ip->tos;
 497                 ip->tos = (old_tos & (priority>>8)) ^ priority;
 498                 if (ip->tos != old_tos)
 499                         ip_send_check(ip);
 500         }
 501 
 502         return answer;
 503 }
 504 
 505 #ifdef CONFIG_IP_MASQUERADE
 506 
 507 static void masq_expire(unsigned long data)
     /* [previous][next][first][last][top][bottom][index][help] */
 508 {
 509         struct ip_masq *ms = (struct ip_masq *)data;
 510         struct ip_masq *old,*cur;
 511         unsigned long flags;
 512 
 513 #ifdef DEBUG_MASQ
 514         printk("Masqueraded %s %lX:%X expired\n",
 515                         strProt[ms->protocol==IPPROTO_TCP],
 516                         ntohl(ms->src),ntohs(ms->sport));
 517 #endif
 518         
 519         save_flags(flags);
 520         cli();
 521 
 522         /* delete from list of hosts */
 523         old = NULL;
 524         cur = ip_msq_hosts;
 525         while (cur!=NULL) {
 526                 if (cur==ms) {
 527                         if (old==NULL) ip_msq_hosts = ms->next;
 528                         else old->next = ms->next;
 529                         kfree_s(ms,sizeof(*ms));
 530                         break;
 531                 }
 532                 old = cur;
 533                 cur=cur->next;
 534         }
 535         restore_flags(flags);
 536 }
 537 
 538 /*
 539  * Create a new masquerade list entry, also allocate an
 540  * unused mport, keeping the portnumber between the
 541  * given boundaries MASQ_BEGIN and MASQ_END.
 542  *
 543  * FIXME: possible deadlock if all free ports are exhausted! 
 544  */
 545 static struct ip_masq *alloc_masq_entry(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 546 {
 547         struct ip_masq *ms, *mst;
 548         unsigned long flags;
 549 
 550         ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), GFP_ATOMIC);
 551         if (ms==NULL) 
 552                 return NULL;
 553 
 554         memset(ms,0,sizeof(*ms));
 555         init_timer(&ms->timer);
 556         ms->timer.data     = (unsigned long)ms;
 557         ms->timer.function = masq_expire;
 558 
 559         save_flags(flags);
 560         cli();
 561         do 
 562         {
 563                 /* Try the next available port number */
 564                 ms->mport = htons(masq_port++);
 565                 if (masq_port==PORT_MASQ_END)
 566                         masq_port = PORT_MASQ_BEGIN;
 567 
 568                 /* Now hunt through the used ports to see if
 569                  * this port is in use... */
 570                 mst = ip_msq_hosts;
 571                 while (mst && mst->mport!=ms->mport)
 572                         mst = mst->next;
 573         }
 574         while (mst!=NULL); 
 575 
 576         /* add new entry in front of list to minimize lookup-time */
 577         ms->next  = ip_msq_hosts;
 578         ip_msq_hosts = ms;
 579         restore_flags(flags);
 580 
 581         return ms;
 582 }
 583 
 584 /*
 585  * When passing an FTP 'PORT' command, try to replace the IP
 586  * address with an newly assigned (masquereded) port on this
 587  * host, so the ftp-data connect FROM the site will succeed...
 588  *
 589  * Also, when the size of the packet changes, create an delta
 590  * offset, which will be added to every th->seq (and subtracted for
 591  * (th->acqseq) whose seq > init_seq.
 592  *
 593  * Not for the faint of heart!
 594  */
 595 
 596 static struct sk_buff *revamp(struct sk_buff *skb, struct device *dev, struct ip_masq *ftp)
     /* [previous][next][first][last][top][bottom][index][help] */
 597 {
 598         struct iphdr *iph = skb->h.iph;
 599         struct tcphdr *th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
 600         struct sk_buff *skb2;
 601         char *p, *data = (char *)&th[1];
 602         unsigned char p1,p2,p3,p4,p5,p6;
 603         unsigned long from;
 604         unsigned short port;
 605         struct ip_masq *ms;
 606         char buf[24];           /* xxx.xxx.xxx.xxx,ppp,ppp\000 */
 607         int diff;
 608         __u32 seq;
 609         
 610         /*
 611          * Adjust seq with delta-offset for all packets after the most recent resized PORT command
 612          * and with previous_delta offset for all packets before most recent resized PORT
 613          */
 614         
 615         /*
 616          * seq & seq_ack are in network byte order; need conversion before comparing
 617          */
 618         seq=ntohl(th->seq);
 619         if (ftp->delta || ftp->previous_delta)
 620         {
 621                 if(after(seq,ftp->init_seq) ) 
 622                 {
 623                         th->seq = htonl(seq + ftp->delta);
 624 #ifdef DEBUG_MASQ
 625                         printk("masq_revamp : added delta (%d) to seq\n",ftp->delta);
 626 #endif
 627                 }
 628                 else
 629                 {
 630                         th->seq = htonl(seq + ftp->previous_delta);
 631 #ifdef DEBUG_MASQ
 632                         printk("masq_revamp : added previous_delta (%d) to seq\n",ftp->previous_delta);
 633 #endif
 634                 }
 635         }
 636 
 637         while (skb->len - ((unsigned char *)data - skb->h.raw) > 18)
 638         {
 639                 if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) 
 640                 {
 641                         data ++;
 642                         continue;
 643                 }
 644                 p = data+5;
 645                 p1 = simple_strtoul(data+5,&data,10);
 646                 if (*data!=',')
 647                         continue;
 648                 p2 = simple_strtoul(data+1,&data,10);
 649                 if (*data!=',')
 650                         continue;
 651                 p3 = simple_strtoul(data+1,&data,10);
 652                 if (*data!=',')
 653                         continue;
 654                 p4 = simple_strtoul(data+1,&data,10);
 655                 if (*data!=',')
 656                         continue;
 657                 p5 = simple_strtoul(data+1,&data,10);
 658                 if (*data!=',')
 659                         continue;
 660                 p6 = simple_strtoul(data+1,&data,10);
 661                 if (*data!='\r' && *data!='\n')
 662                         continue;
 663 
 664                 from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
 665                 port = (p5<<8) | p6;
 666 #ifdef MASQ_DEBUG
 667                 printk("PORT %lX:%X detected\n",from,port);
 668 #endif  
 669                 /*
 670                  * Now create an masquerade entry for it
 671                  */
 672                 ms = alloc_masq_entry();
 673                 if (ms==NULL)
 674                         return skb;
 675                 ms->protocol = IPPROTO_TCP;
 676                 ms->src      = htonl(from);     /* derived from PORT cmd */
 677                 ms->sport    = htons(port);     /* derived from PORT cmd */
 678                 ms->dst      = iph->daddr;
 679                 /*
 680                  * Hardcoding 20 as dport is not always correct
 681                  * At least 1 Windows ftpd uses a random port number instead of 20
 682                  * Leave it undefined for now & wait for the first connection request to fill it out
 683                  */ 
 684                 ms->dport    = htons(FTP_DPORT_TBD);    /* ftp-data */
 685                 ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN;
 686                 add_timer(&ms->timer);
 687 
 688                 /*
 689                  * Replace the old PORT with the new one
 690                  */
 691                 from = ntohl(dev->pa_addr);
 692                 port = ntohs(ms->mport);
 693                 sprintf(buf,"%ld,%ld,%ld,%ld,%d,%d",
 694                         from>>24&255,from>>16&255,from>>8&255,from&255,
 695                         port>>8&255,port&255);
 696 
 697                 /*
 698                  * Calculate required delta-offset to keep TCP happy
 699                  */
 700                 
 701                 diff = strlen(buf) - (data-p);
 702                 
 703                 /*
 704                  *      No shift.
 705                  */
 706                  
 707                 if (diff==0) 
 708                 {
 709                         /*
 710                          * simple case, just replace the old PORT cmd
 711                          */
 712                         memcpy(p,buf,strlen(buf));
 713                         return skb;
 714                 }
 715  
 716                 /*
 717                  *      If the PORT command we have fiddled is the first, or is a
 718                  *      resend don't do the delta shift again. Doesn't work for
 719                  *      pathological cases, but we would need a history for that.
 720                  *      Also fails if you send 2^31 bytes of data down the link 
 721                  *      after the first port command.
 722                  *
 723                  *      FIXME: use ftp->init_seq_valid - 0 is a valid sequence.
 724                  */
 725                  
 726                 if(!ftp->init_seq || after(seq,ftp->init_seq) )
 727                 {
 728                         ftp->previous_delta=ftp->delta;
 729                         ftp->delta+=diff;
 730                         ftp->init_seq = seq;
 731                 }
 732                 
 733                 /*
 734                  * Sizes differ, make a copy
 735                  */
 736 #ifdef DEBUG_MASQ
 737                 printk("MASQUERADE: resizing needed for %d bytes (%ld)\n",diff, skb->len);
 738 #endif
 739                 skb2 = alloc_skb(MAX_HEADER + skb->len+diff, GFP_ATOMIC);
 740                 if (skb2 == NULL) {
 741                         printk("MASQUERADE: No memory available\n");
 742                         return skb;
 743                 }
 744                 skb2->free = skb->free;
 745                 skb_reserve(skb2,MAX_HEADER);
 746                 skb_put(skb2,skb->len + diff);
 747                 skb2->h.raw = skb2->data + (skb->h.raw - skb->data);
 748                 iph=skb2->h.iph;
 749                 /*
 750                  *      Mend the IP header too
 751                  */
 752                 iph->tot_len = htons(diff+ntohs(iph->tot_len));
 753                 iph->check = 0;
 754                 iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 755  
 756                 /*
 757                  *      Copy the packet data into the new buffer.
 758                  *      Thereby replacing the PORT cmd.
 759                  */
 760                 memcpy(skb2->data, skb->data, (p - (char *)skb->data));
 761                 memcpy(&skb2->data[(p - (char *)skb->data)], buf, strlen(buf));
 762                 memcpy(&skb2->data[(p - (char *)skb->data) + strlen(buf)], data,
 763                         skb->len - (data-(char *)skb->data));
 764 
 765                 /*
 766                  * Update tot_len field in ip header !
 767                  * Sequence numbers were allready modified in original packet
 768                  */
 769                 iph->tot_len = htons(skb->len + diff);
 770 
 771                 /*
 772                  * Problem, how to replace the new skb with old one,
 773                  * preferably inplace, so all the pointers in the
 774                  * calling tree keep ok :(
 775                  */
 776                 kfree_skb(skb, FREE_WRITE);
 777                 return skb2;
 778         }
 779         return skb;
 780 }
 781 
 782 static void recalc_check(struct udphdr *uh, unsigned long saddr,
     /* [previous][next][first][last][top][bottom][index][help] */
 783         unsigned long daddr, int len)
 784 {
 785         uh->check=0;
 786         uh->check=csum_tcpudp_magic(saddr,daddr,len,
 787                 IPPROTO_UDP, csum_partial((char *)uh,len,0));
 788         if(uh->check==0)
 789                 uh->check=0xFFFF;
 790 }
 791         
 792 void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 793 {
 794         struct sk_buff  *skb=*skb_ptr;
 795         struct iphdr    *iph = skb->h.iph;
 796         unsigned short  *portptr;
 797         struct ip_masq  *ms;
 798         int             size;
 799 
 800         /*
 801          * We can only masquerade protocols with ports...
 802          */
 803 
 804         if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
 805                 return;
 806  
 807         /*
 808          *      Now hunt the list to see if we have an old entry
 809          */
 810 
 811         portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]);
 812         ms = ip_msq_hosts;
 813 
 814 #ifdef DEBUG_MASQ
 815         printk("Outgoing %s %lX:%X -> %lX:%X\n",
 816                 strProt[iph->protocol==IPPROTO_TCP],
 817                 ntohl(iph->saddr), ntohs(portptr[0]),
 818                 ntohl(iph->daddr), ntohs(portptr[1]));
 819 #endif
 820         while (ms!=NULL) 
 821         {
 822                 if (iph->protocol == ms->protocol &&
 823                     iph->saddr == ms->src   && iph->daddr == ms->dst &&
 824                     portptr[0] == ms->sport && portptr[1] == ms->dport) 
 825                 {
 826                         del_timer(&ms->timer);
 827                         break;
 828                 }
 829                 ms = ms->next;
 830         }
 831 
 832         /*
 833          *      Nope, not found, create a new entry for it
 834          */
 835          
 836         if (ms==NULL) 
 837         {
 838                 ms = alloc_masq_entry();
 839                 if (ms==NULL) 
 840                 {
 841                         printk("MASQUERADE: no memory left !\n");
 842                         return;
 843                 }
 844                 ms->protocol = iph->protocol;
 845                 ms->src      = iph->saddr;
 846                 ms->dst      = iph->daddr;
 847                 ms->sport    = portptr[0];
 848                 ms->dport    = portptr[1];
 849         }
 850  
 851         /*
 852          *      Change the fragments origin
 853          */
 854          
 855         size = skb->len - ((unsigned char *)portptr - skb->h.raw);
 856         iph->saddr = dev->pa_addr; /* my own address */
 857         portptr[0] = ms->mport;
 858  
 859         /*
 860          *      Adjust packet accordingly to protocol
 861          */
 862          
 863         if (iph->protocol==IPPROTO_UDP) 
 864         {
 865                 ms->timer.expires = jiffies+MASQUERADE_EXPIRE_UDP;
 866                 recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
 867         }
 868         else 
 869         {
 870                 struct tcphdr *th;
 871                 if (portptr[1]==htons(21)) 
 872                 {
 873                         skb = revamp(*skb_ptr, dev, ms);
 874                         *skb_ptr = skb;
 875                         iph = skb->h.iph;
 876                         portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]);
 877                         size = skb->len - ((unsigned char *)portptr-skb->h.raw);
 878                 }
 879                 th = (struct tcphdr *)portptr;
 880  
 881                 /*
 882                  *      Timeout depends if FIN packet was seen
 883                  */
 884                 if (ms->sawfin || th->fin) 
 885                 {
 886                         ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN;
 887                         ms->sawfin = 1;
 888                 }
 889                 else ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP;
 890  
 891                 tcp_send_check(th,iph->saddr,iph->daddr,size,skb->sk);
 892         }
 893         add_timer(&ms->timer);
 894         ip_send_check(iph);
 895  
 896  #ifdef DEBUG_MASQ
 897         printk("O-routed from %lX:%X over %s\n",ntohl(dev->pa_addr),ntohs(ms->mport),dev->name);
 898  #endif
 899  }
 900  
 901  /*
 902   *     Check if it's an masqueraded port, look it up,
 903   *     and send it on it's way...
 904   *
 905   *     Better not have many hosts using the designated portrange
 906   *     as 'normal' ports, or you'll be spending lots of time in
 907   *     this function.
 908   */
 909 
 910 int ip_fw_demasquerade(struct sk_buff *skb_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 911 {
 912         struct iphdr    *iph = skb_ptr->h.iph;
 913         unsigned short  *portptr;
 914         struct ip_masq  *ms;
 915         struct tcphdr   *th = (struct tcphdr *)(skb_ptr->h.raw+(iph->ihl<<2));
 916  
 917         if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
 918                 return 0;
 919  
 920         portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]);
 921         if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
 922             ntohs(portptr[1]) > PORT_MASQ_END)
 923                 return 0;
 924  
 925 #ifdef DEBUG_MASQ
 926         printk("Incoming %s %lX:%X -> %lX:%X\n",
 927                 strProt[iph->protocol==IPPROTO_TCP],
 928                 ntohl(iph->saddr), ntohs(portptr[0]),
 929                 ntohl(iph->daddr), ntohs(portptr[1]));
 930 #endif
 931 
 932         /*
 933          * reroute to original host:port if found...
 934          *
 935          * NB. Cannot check destination address, just for the incoming port.
 936          * reason: archie.doc.ac.uk has 6 interfaces, you send to
 937          * phoenix and get a reply from any other interface(==dst)!
 938          *
 939          * [Only for UDP] - AC
 940          */
 941         ms = ip_msq_hosts;
 942         while (ms!=NULL) 
 943         {
 944                 if (iph->protocol==ms->protocol &&
 945                     (iph->saddr==ms->dst || iph->protocol==IPPROTO_UDP) && 
 946                     (ms->dport==htons(FTP_DPORT_TBD) || portptr[0]==ms->dport) &&
 947                     portptr[1]==ms->mport)
 948                 {
 949                 
 950                         int size = skb_ptr->len - ((unsigned char *)portptr - skb_ptr->h.raw);
 951                         iph->daddr = ms->src;
 952                         portptr[1] = ms->sport;
 953                         
 954                         if(ms->dport==htons(FTP_DPORT_TBD))
 955                         {
 956                                 ms->dport=portptr[0];
 957 #ifdef DEBUG_MASQ
 958                                 printk("demasq : Filled out dport entry (%d) based on initial connect attempt from FTP deamon\n",ntohs(ms->dport));
 959 #endif
 960                         }
 961 
 962                         /*
 963                          * Yug! adjust UDP/TCP and IP checksums
 964                          */
 965                         if (iph->protocol==IPPROTO_UDP)
 966                                 recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
 967                         else
 968                         {
 969                                 __u32 ack_seq;
 970                                 /*
 971                                  * Adjust ack_seq with delta-offset for
 972                                  * the packets AFTER most recent PORT command has caused a shift
 973                                  * for packets before most recent PORT command, use previous_delta
 974                                  */
 975 #ifdef DEBUG_MASQ
 976                                 printk("demasq : delta=%d ; previous_delta=%d ; init_seq=%lX ; ack_seq=%lX ; after=%d\n",ms->delta,ms->previous_delta,ntohl(ms->init_seq),ntohl(th->ack_seq),after(ntohl(th->ack_seq),ntohl(ms->init_seq)));
 977 #endif
 978                                 ack_seq=ntohl(th->ack_seq);
 979                                 if (ms->delta || ms->previous_delta)
 980                                 {
 981                                         if(after(ack_seq,ms->init_seq))
 982                                         {
 983                                                 th->ack_seq = htonl(ack_seq-ms->delta);
 984 #ifdef DEBUG_MASQ
 985                                                 printk("demasq : substracted delta (%d) from ack_seq\n",ms->delta);
 986 #endif
 987                                         }
 988                                         else
 989                                         {
 990                                                 th->ack_seq = htonl(ack_seq-ms->previous_delta);
 991 #ifdef DEBUG_MASQ
 992                                                 printk("demasq : substracted previous_delta (%d) from ack_seq\n",ms->previous_delta);
 993 #endif
 994                                         }
 995                                 }
 996                                 tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb_ptr->sk);
 997                         }
 998                         ip_send_check(iph);
 999 #ifdef DEBUG_MASQ
1000                         printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1]));
1001 #endif
1002                         return 1;
1003                 }
1004                 ms = ms->next;
1005         }
1006  
1007         /* sorry, all this trouble for a no-hit :) */
1008         return 0;
1009 }
1010 #endif
1011   
1012 
1013 
1014 static void zero_fw_chain(struct ip_fw *chainptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1015 {
1016         struct ip_fw *ctmp=chainptr;
1017         while(ctmp) 
1018         {
1019                 ctmp->fw_pcnt=0L;
1020                 ctmp->fw_bcnt=0L;
1021                 ctmp=ctmp->fw_next;
1022         }
1023 }
1024 
1025 static void free_fw_chain(struct ip_fw *volatile* chainptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1026 {
1027         unsigned long flags;
1028         save_flags(flags);
1029         cli();
1030         while ( *chainptr != NULL ) 
1031         {
1032                 struct ip_fw *ftmp;
1033                 ftmp = *chainptr;
1034                 *chainptr = ftmp->fw_next;
1035                 kfree_s(ftmp,sizeof(*ftmp));
1036         }
1037         restore_flags(flags);
1038 }
1039 
1040 /* Volatiles to keep some of the compiler versions amused */
1041 
1042 static int add_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1043 {
1044         struct ip_fw *ftmp;
1045         struct ip_fw *chtmp=NULL;
1046         struct ip_fw *volatile chtmp_prev=NULL;
1047         unsigned long flags;
1048         unsigned long m_src_mask,m_dst_mask;
1049         unsigned long n_sa,n_da,o_sa,o_da,o_sm,o_dm,n_sm,n_dm;
1050         unsigned short n_sr,n_dr,o_sr,o_dr; 
1051         unsigned short oldkind,newkind;
1052         int addb4=0;
1053         int n_o,n_n;
1054 
1055         save_flags(flags);
1056 
1057         ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC );
1058         if ( ftmp == NULL ) 
1059         {
1060 #ifdef DEBUG_CONFIG_IP_FIREWALL
1061                 printk("ip_fw_ctl:  malloc said no\n");
1062 #endif
1063                 return( ENOMEM );
1064         }
1065 
1066         memcpy(ftmp, frwl, len);
1067         if (len == sizeof (struct ip_fw_old))
1068                 ftmp->fw_priority = 0xFF00; /* and_mask, xor_mask */
1069 
1070         ftmp->fw_priority = (ftmp->fw_priority & 0xFFFC) | 0x0300;
1071         ftmp->fw_pcnt=0L;
1072         ftmp->fw_bcnt=0L;
1073 
1074         ftmp->fw_next = NULL;
1075 
1076         cli();
1077 
1078         if (*chainptr==NULL)
1079         {
1080                 *chainptr=ftmp;
1081         }
1082         else
1083         {
1084                 chtmp_prev=NULL;
1085                 for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->fw_next) 
1086                 {
1087                         if (ftmp->fw_flg & IP_FW_F_APPEND) {
1088                                 chtmp_prev=chtmp;
1089                                 continue;
1090                         }
1091                         addb4=0;
1092                         newkind=ftmp->fw_flg & IP_FW_F_KIND;
1093                         oldkind=chtmp->fw_flg & IP_FW_F_KIND;
1094         
1095                         if (newkind!=IP_FW_F_ALL 
1096                                 &&  oldkind!=IP_FW_F_ALL
1097                                 &&  oldkind!=newkind) 
1098                         {
1099                                 chtmp_prev=chtmp;
1100                                 continue;
1101                         }
1102 
1103                         /*
1104                          *      Very very *UGLY* code...
1105                          *      Sorry,but i had to do this....
1106                          */
1107 
1108                         n_sa=ntohl(ftmp->fw_src.s_addr);
1109                         n_da=ntohl(ftmp->fw_dst.s_addr);
1110                         n_sm=ntohl(ftmp->fw_smsk.s_addr);
1111                         n_dm=ntohl(ftmp->fw_dmsk.s_addr);
1112 
1113                         o_sa=ntohl(chtmp->fw_src.s_addr);
1114                         o_da=ntohl(chtmp->fw_dst.s_addr);
1115                         o_sm=ntohl(chtmp->fw_smsk.s_addr);
1116                         o_dm=ntohl(chtmp->fw_dmsk.s_addr);
1117 
1118                         m_src_mask = o_sm & n_sm;
1119                         m_dst_mask = o_dm & n_dm;
1120 
1121                         if ((o_sa & m_src_mask) == (n_sa & m_src_mask)) 
1122                         {
1123                                 if (n_sm > o_sm) 
1124                                         addb4++;
1125                                 if (n_sm < o_sm) 
1126                                         addb4--;
1127                         }
1128 
1129                         if ((o_da & m_dst_mask) == (n_da & m_dst_mask)) 
1130                         {
1131                                 if (n_dm > o_dm)
1132                                         addb4++;
1133                                 if (n_dm < o_dm)
1134                                         addb4--;
1135                         }
1136 
1137                         if (((o_da & o_dm) == (n_da & n_dm))
1138                                 &&((o_sa & o_sm) == (n_sa & n_sm)))
1139                         {
1140                                 if (newkind!=IP_FW_F_ALL &&
1141                                         oldkind==IP_FW_F_ALL)
1142                                         addb4++;
1143                                 if (newkind==oldkind && (oldkind==IP_FW_F_TCP
1144                                         ||  oldkind==IP_FW_F_UDP)) 
1145                                 {
1146 
1147                                         /*
1148                                          *      Here the main idea is to check the size
1149                                          *      of port range which the frwl covers
1150                                          *      We actually don't check their values but
1151                                          *      just the wideness of range they have
1152                                          *      so that less wide ranges or single ports
1153                                          *      go first and wide ranges go later. No ports
1154                                          *      at all treated as a range of maximum number
1155                                          *      of ports.
1156                                          */
1157 
1158                                         if (ftmp->fw_flg & IP_FW_F_SRNG) 
1159                                                 n_sr=ftmp->fw_pts[1]-ftmp->fw_pts[0];
1160                                         else 
1161                                                 n_sr=(ftmp->fw_nsp)?
1162                                                         ftmp->fw_nsp : 0xFFFF;
1163                                                 
1164                                         if (chtmp->fw_flg & IP_FW_F_SRNG) 
1165                                                 o_sr=chtmp->fw_pts[1]-chtmp->fw_pts[0];
1166                                         else 
1167                                                 o_sr=(chtmp->fw_nsp)?chtmp->fw_nsp : 0xFFFF;
1168 
1169                                         if (n_sr<o_sr)
1170                                                 addb4++;
1171                                         if (n_sr>o_sr)
1172                                                 addb4--;
1173                                         
1174                                         n_n=ftmp->fw_nsp;
1175                                         n_o=chtmp->fw_nsp;
1176         
1177                                         /*
1178                                          * Actually this cannot happen as the frwl control
1179                                          * procedure checks for number of ports in source and
1180                                          * destination range but we will try to be more safe.
1181                                          */
1182                                          
1183                                         if ((n_n>(IP_FW_MAX_PORTS-2)) ||
1184                                                 (n_o>(IP_FW_MAX_PORTS-2)))
1185                                                 goto skip_check;
1186 
1187                                         if (ftmp->fw_flg & IP_FW_F_DRNG) 
1188                                                n_dr=ftmp->fw_pts[n_n+1]-ftmp->fw_pts[n_n];
1189                                         else 
1190                                                n_dr=(ftmp->fw_ndp)? ftmp->fw_ndp : 0xFFFF;
1191 
1192                                         if (chtmp->fw_flg & IP_FW_F_DRNG) 
1193                                                 o_dr=chtmp->fw_pts[n_o+1]-chtmp->fw_pts[n_o];
1194                                         else 
1195                                                 o_dr=(chtmp->fw_ndp)? chtmp->fw_ndp : 0xFFFF;
1196                                         if (n_dr<o_dr)
1197                                                 addb4++;
1198                                         if (n_dr>o_dr)
1199                                                 addb4--;
1200 skip_check:
1201                                 }
1202                                 /* finally look at the interface address */
1203                                 if ((addb4 == 0) && ftmp->fw_via.s_addr &&
1204                                                 !(chtmp->fw_via.s_addr))
1205                                         addb4++;
1206                         }
1207                         if (addb4>0) 
1208                         {
1209                                 if (chtmp_prev) 
1210                                 {
1211                                         chtmp_prev->fw_next=ftmp; 
1212                                         ftmp->fw_next=chtmp;
1213                                 } 
1214                                 else 
1215                                 {
1216                                         *chainptr=ftmp;
1217                                         ftmp->fw_next=chtmp;
1218                                 }
1219                                 restore_flags(flags);
1220                                 return 0;
1221                         }
1222                         chtmp_prev=chtmp;
1223                 }
1224         }
1225         
1226         if (chtmp_prev)
1227                 chtmp_prev->fw_next=ftmp;
1228         else
1229                 *chainptr=ftmp;
1230         restore_flags(flags);
1231         return(0);
1232 }
1233 
1234 static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl)
     /* [previous][next][first][last][top][bottom][index][help] */
1235 {
1236         struct ip_fw    *ftmp,*ltmp;
1237         unsigned short  tport1,tport2,tmpnum;
1238         char            matches,was_found;
1239         unsigned long   flags;
1240 
1241         save_flags(flags);
1242         cli();
1243 
1244         ftmp=*chainptr;
1245 
1246         if ( ftmp == NULL ) 
1247         {
1248 #ifdef DEBUG_CONFIG_IP_FIREWALL
1249                 printk("ip_fw_ctl:  chain is empty\n");
1250 #endif
1251                 restore_flags(flags);
1252                 return( EINVAL );
1253         }
1254 
1255         ltmp=NULL;
1256         was_found=0;
1257 
1258         while( ftmp != NULL )
1259         {
1260                 matches=1;
1261              if (ftmp->fw_src.s_addr!=frwl->fw_src.s_addr 
1262                      ||  ftmp->fw_dst.s_addr!=frwl->fw_dst.s_addr
1263                      ||  ftmp->fw_smsk.s_addr!=frwl->fw_smsk.s_addr
1264                      ||  ftmp->fw_dmsk.s_addr!=frwl->fw_dmsk.s_addr
1265                      ||  ftmp->fw_via.s_addr!=frwl->fw_via.s_addr
1266                      ||  ftmp->fw_flg!=frwl->fw_flg)
1267                         matches=0;
1268 
1269                 tport1=ftmp->fw_nsp+ftmp->fw_ndp;
1270                 tport2=frwl->fw_nsp+frwl->fw_ndp;
1271                 if (tport1!=tport2)
1272                         matches=0;
1273                 else if (tport1!=0)
1274                 {
1275                         for (tmpnum=0;tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS;tmpnum++)
1276                         if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum])
1277                                 matches=0;
1278                 }
1279                 if(matches)
1280                 {
1281                         was_found=1;
1282                         if (ltmp)
1283                         {
1284                                 ltmp->fw_next=ftmp->fw_next;
1285                                 kfree_s(ftmp,sizeof(*ftmp));
1286                                 ftmp=ltmp->fw_next;
1287                         }
1288                         else
1289                         {
1290                                 *chainptr=ftmp->fw_next; 
1291                                 kfree_s(ftmp,sizeof(*ftmp));
1292                                 ftmp=*chainptr;
1293                         }       
1294                 }
1295                 else
1296                 {
1297                         ltmp = ftmp;
1298                         ftmp = ftmp->fw_next;
1299                  }
1300         }
1301         restore_flags(flags);
1302         if (was_found)
1303                 return 0;
1304         else
1305                 return(EINVAL);
1306 }
1307 
1308 #endif  /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
1309 
1310 struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1311 {
1312 
1313         if ( len != sizeof(struct ip_fw) && len != sizeof(struct ip_fw_old))
1314         {
1315 #ifdef DEBUG_CONFIG_IP_FIREWALL
1316                 printk("ip_fw_ctl: len=%d, want %d\n",len, sizeof(struct ip_fw));
1317 #endif
1318                 return(NULL);
1319         }
1320 
1321         if ( (frwl->fw_flg & ~IP_FW_F_MASK) != 0 )
1322         {
1323 #ifdef DEBUG_CONFIG_IP_FIREWALL
1324                 printk("ip_fw_ctl: undefined flag bits set (flags=%x)\n",
1325                         frwl->fw_flg);
1326 #endif
1327                 return(NULL);
1328         }
1329 
1330         if ( (frwl->fw_flg & IP_FW_F_SRNG) && frwl->fw_nsp < 2 ) 
1331         {
1332 #ifdef DEBUG_CONFIG_IP_FIREWALL
1333                 printk("ip_fw_ctl: src range set but fw_nsp=%d\n",
1334                         frwl->fw_nsp);
1335 #endif
1336                 return(NULL);
1337         }
1338 
1339         if ( (frwl->fw_flg & IP_FW_F_DRNG) && frwl->fw_ndp < 2 ) 
1340         {
1341 #ifdef DEBUG_CONFIG_IP_FIREWALL
1342                 printk("ip_fw_ctl: dst range set but fw_ndp=%d\n",
1343                         frwl->fw_ndp);
1344 #endif
1345                 return(NULL);
1346         }
1347 
1348         if ( frwl->fw_nsp + frwl->fw_ndp > IP_FW_MAX_PORTS ) 
1349         {
1350 #ifdef DEBUG_CONFIG_IP_FIREWALL
1351                 printk("ip_fw_ctl: too many ports (%d+%d)\n",
1352                         frwl->fw_nsp,frwl->fw_ndp);
1353 #endif
1354                 return(NULL);
1355         }
1356 
1357         return frwl;
1358 }
1359 
1360 
1361 
1362 
1363 #ifdef CONFIG_IP_ACCT
1364 
1365 #if 0
1366 void ip_acct_cnt(struct iphdr *iph, struct device *dev, struct ip_fw *f)
     /* [previous][next][first][last][top][bottom][index][help] */
1367 {
1368         (void) ip_fw_chk(iph, dev, f, 0, 1);
1369         return;
1370 }
1371 #endif
1372 
1373 int ip_acct_ctl(int stage, void *m, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1374 {
1375         if ( stage == IP_ACCT_FLUSH )
1376         {
1377                 free_fw_chain(&ip_acct_chain);
1378                 return(0);
1379         }  
1380         if ( stage == IP_ACCT_ZERO )
1381         {
1382                 zero_fw_chain(ip_acct_chain);
1383                 return(0);
1384         }
1385         if ( stage == IP_ACCT_ADD
1386           || stage == IP_ACCT_DEL
1387            )
1388         {
1389                 struct ip_fw *frwl;
1390 
1391                 if (!(frwl=check_ipfw_struct(m,len)))
1392                         return (EINVAL);
1393 
1394                 switch (stage) 
1395                 {
1396                         case IP_ACCT_ADD:
1397                                 return( add_to_chain(&ip_acct_chain,frwl,len));
1398                         case IP_ACCT_DEL:
1399                                 return( del_from_chain(&ip_acct_chain,frwl));
1400                         default:
1401                                 /*
1402                                  *      Should be panic but... (Why ??? - AC)
1403                                  */
1404 #ifdef DEBUG_CONFIG_IP_FIREWALL
1405                                 printk("ip_acct_ctl:  unknown request %d\n",stage);
1406 #endif
1407                                 return(EINVAL);
1408                 }
1409         }
1410 #ifdef DEBUG_CONFIG_IP_FIREWALL
1411         printk("ip_acct_ctl:  unknown request %d\n",stage);
1412 #endif
1413         return(EINVAL);
1414 }
1415 #endif
1416 
1417 #ifdef CONFIG_IP_FIREWALL
1418 int ip_fw_ctl(int stage, void *m, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1419 {
1420         int ret;
1421 
1422         if ( stage == IP_FW_FLUSH_BLK )
1423         {
1424                 free_fw_chain(&ip_fw_blk_chain);
1425                 return(0);
1426         }  
1427 
1428         if ( stage == IP_FW_FLUSH_FWD )
1429         {
1430                 free_fw_chain(&ip_fw_fwd_chain);
1431                 return(0);
1432         }  
1433 
1434         if ( stage == IP_FW_ZERO_BLK )
1435         {
1436                 zero_fw_chain(ip_fw_blk_chain);
1437                 return(0);
1438         }  
1439 
1440         if ( stage == IP_FW_ZERO_FWD )
1441         {
1442                 zero_fw_chain(ip_fw_fwd_chain);
1443                 return(0);
1444         }  
1445 
1446         if ( stage == IP_FW_POLICY_BLK || stage == IP_FW_POLICY_FWD )
1447         {
1448                 int *tmp_policy_ptr;
1449                 tmp_policy_ptr=(int *)m;
1450                 if ( stage == IP_FW_POLICY_BLK )
1451                         ip_fw_blk_policy=*tmp_policy_ptr;
1452                 else
1453                         ip_fw_fwd_policy=*tmp_policy_ptr;
1454                 return 0;
1455         }
1456 
1457         if ( stage == IP_FW_CHK_BLK || stage == IP_FW_CHK_FWD )
1458         {
1459                 struct device viadev;
1460                 struct ip_fwpkt *ipfwp;
1461                 struct iphdr *ip;
1462 
1463                 if ( len < sizeof(struct ip_fwpkt) )
1464                 {
1465 #ifdef DEBUG_CONFIG_IP_FIREWALL
1466                         printk("ip_fw_ctl: length=%d, expected %d\n",
1467                                 len, sizeof(struct ip_fwpkt));
1468 #endif
1469                         return( EINVAL );
1470                 }
1471 
1472                 ipfwp = (struct ip_fwpkt *)m;
1473                 ip = &(ipfwp->fwp_iph);
1474 
1475                 if ( ip->ihl != sizeof(struct iphdr) / sizeof(int))
1476                 {
1477 #ifdef DEBUG_CONFIG_IP_FIREWALL
1478                         printk("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl,
1479                                         sizeof(struct iphdr)/sizeof(int));
1480 #endif
1481                         return(EINVAL);
1482                 }
1483 
1484                 viadev.pa_addr = ipfwp->fwp_via.s_addr;
1485 
1486                 if ((ret = ip_fw_chk(ip, &viadev,
1487                         stage == IP_FW_CHK_BLK ?
1488                         ip_fw_blk_chain : ip_fw_fwd_chain,
1489                         stage == IP_FW_CHK_BLK ?
1490                         ip_fw_blk_policy : ip_fw_fwd_policy, 2 )) > 0
1491                    )
1492                         return(0);
1493                 else if (ret == -1)     
1494                         return(ECONNREFUSED);
1495                 else
1496                         return(ETIMEDOUT);
1497         }
1498 
1499 /*
1500  *      Here we really working hard-adding new elements
1501  *      to blocking/forwarding chains or deleting 'em
1502  */
1503 
1504         if ( stage == IP_FW_ADD_BLK || stage == IP_FW_ADD_FWD
1505                 || stage == IP_FW_DEL_BLK || stage == IP_FW_DEL_FWD
1506                 )
1507         {
1508                 struct ip_fw *frwl;
1509                 frwl=check_ipfw_struct(m,len);
1510                 if (frwl==NULL)
1511                         return (EINVAL);
1512                 
1513                 switch (stage) 
1514                 {
1515                         case IP_FW_ADD_BLK:
1516                                 return(add_to_chain(&ip_fw_blk_chain,frwl,len));
1517                         case IP_FW_ADD_FWD:
1518                                 return(add_to_chain(&ip_fw_fwd_chain,frwl,len));
1519                         case IP_FW_DEL_BLK:
1520                                 return(del_from_chain(&ip_fw_blk_chain,frwl));
1521                         case IP_FW_DEL_FWD: 
1522                                 return(del_from_chain(&ip_fw_fwd_chain,frwl));
1523                         default:
1524                         /*
1525                          *      Should be panic but... (Why are BSD people panic obsessed ??)
1526                          */
1527 #ifdef DEBUG_CONFIG_IP_FIREWALL
1528                                 printk("ip_fw_ctl:  unknown request %d\n",stage);
1529 #endif
1530                                 return(EINVAL);
1531                 }
1532         } 
1533 
1534 #ifdef DEBUG_CONFIG_IP_FIREWALL
1535         printk("ip_fw_ctl:  unknown request %d\n",stage);
1536 #endif
1537         return(EINVAL);
1538 }
1539 #endif /* CONFIG_IP_FIREWALL */
1540 
1541 #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
1542 
1543 static int ip_chain_procinfo(int stage, char *buffer, char **start,
     /* [previous][next][first][last][top][bottom][index][help] */
1544                              off_t offset, int length, int reset)
1545 {
1546         off_t pos=0, begin=0;
1547         struct ip_fw *i;
1548         unsigned long flags;
1549         int len, p;
1550         
1551 
1552         switch(stage)
1553         {
1554 #ifdef CONFIG_IP_FIREWALL
1555                 case IP_INFO_BLK:
1556                         i = ip_fw_blk_chain;
1557                         len=sprintf(buffer, "IP firewall block rules, default %d\n",
1558                                 ip_fw_blk_policy);
1559                         break;
1560                 case IP_INFO_FWD:
1561                         i = ip_fw_fwd_chain;
1562                         len=sprintf(buffer, "IP firewall forward rules, default %d\n",
1563                                 ip_fw_fwd_policy);
1564                         break;
1565 #endif
1566 #ifdef CONFIG_IP_ACCT
1567                 case IP_INFO_ACCT:
1568                         i = ip_acct_chain;
1569                         len=sprintf(buffer,"IP accounting rules\n");
1570                         break;
1571 #endif
1572                 default:
1573                         /* this should never be reached, but safety first... */
1574                         i = NULL;
1575                         len=0;
1576                         break;
1577         }
1578 
1579         save_flags(flags);
1580         cli();
1581         
1582         while(i!=NULL)
1583         {
1584                 len+=sprintf(buffer+len,"%08lX/%08lX->%08lX/%08lX %08lX %X ",
1585                         ntohl(i->fw_src.s_addr),ntohl(i->fw_smsk.s_addr),
1586                         ntohl(i->fw_dst.s_addr),ntohl(i->fw_dmsk.s_addr),
1587                         ntohl(i->fw_via.s_addr),i->fw_flg);
1588                 len+=sprintf(buffer+len,"%u %u %-9lu %-9lu",
1589                         i->fw_nsp,i->fw_ndp, i->fw_pcnt,i->fw_bcnt);
1590                 for (p = 0; p < IP_FW_MAX_PORTS; p++)
1591                         len+=sprintf(buffer+len, " %u", i->fw_pts[p]);
1592                 len+=sprintf(buffer+len, " M%04X", i->fw_priority);
1593                 buffer[len++]='\n';
1594                 buffer[len]='\0';
1595                 pos=begin+len;
1596                 if(pos<offset)
1597                 {
1598                         len=0;
1599                         begin=pos;
1600                 }
1601                 else if(reset)
1602                 {
1603                         /* This needs to be done at this specific place! */
1604                         i->fw_pcnt=0L;
1605                         i->fw_bcnt=0L;
1606                 }
1607                 if(pos>offset+length)
1608                         break;
1609                 i=i->fw_next;
1610         }
1611         restore_flags(flags);
1612         *start=buffer+(offset-begin);
1613         len-=(offset-begin);
1614         if(len>length)
1615                 len=length;     
1616         return len;
1617 }
1618 #endif
1619 
1620 #ifdef CONFIG_IP_ACCT
1621 
1622 static int ip_acct_procinfo(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
1623                             int length, int reset)
1624 {
1625         return ip_chain_procinfo(IP_INFO_ACCT, buffer,start, offset,length,
1626                                  reset);
1627 }
1628 
1629 #endif
1630 
1631 #ifdef CONFIG_IP_FIREWALL
1632 
1633 static int ip_fw_blk_procinfo(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
1634                               int length, int reset)
1635 {
1636         return ip_chain_procinfo(IP_INFO_BLK, buffer,start,offset,length,
1637                                  reset);
1638 }
1639 
1640 static int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
1641                               int length, int reset)
1642 {
1643         return ip_chain_procinfo(IP_INFO_FWD, buffer,start,offset,length,
1644                                  reset);
1645 }
1646 #endif
1647 
1648 #ifdef CONFIG_IP_MASQUERADE
1649 
1650 static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
1651                               int length, int unused)
1652 {
1653         off_t pos=0, begin=0;
1654         struct ip_masq *ms;
1655         unsigned long flags;
1656         int len=0;
1657         
1658         len=sprintf(buffer,"Prc FromIP   FPrt ToIP     TPrt Masq Init-seq Delta PDelta Expires\n"); 
1659         save_flags(flags);
1660         cli();
1661         
1662         ms=ip_msq_hosts;
1663         while (ms!=NULL) 
1664         {
1665                 int timer_active = del_timer(&ms->timer);
1666                 if (!timer_active)
1667                         ms->timer.expires = jiffies;
1668                 len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %5d %5d %lu\n",
1669                         strProt[ms->protocol==IPPROTO_TCP],
1670                         ntohl(ms->src),ntohs(ms->sport),
1671                         ntohl(ms->dst),ntohs(ms->dport),
1672                         ntohs(ms->mport),
1673                         ms->init_seq,ms->delta,ms->previous_delta,ms->timer.expires-jiffies);
1674                 if (timer_active)
1675                         add_timer(&ms->timer);
1676 
1677                 pos=begin+len;
1678                 if(pos<offset) 
1679                 {
1680                         len=0;
1681                         begin=pos;
1682                 }
1683                 if(pos>offset+length)
1684                         break;
1685                 ms=ms->next;
1686         }
1687         restore_flags(flags);
1688         *start=buffer+(offset-begin);
1689         len-=(offset-begin);
1690         if(len>length)
1691                 len=length;
1692         return len;
1693 }
1694   
1695 #endif
1696 
1697 #ifdef CONFIG_IP_FIREWALL
1698 /*
1699  *      Interface to the generic firewall chains.
1700  */
1701  
1702 int ipfw_input_check(struct firewall_ops *this, int pf, struct sk_buff *skb, void *phdr)
     /* [previous][next][first][last][top][bottom][index][help] */
1703 {
1704         return ip_fw_chk(phdr, skb->dev, ip_fw_blk_chain, ip_fw_blk_policy, 0);
1705 }
1706 
1707 int ipfw_forward_check(struct firewall_ops *this, int pf, struct sk_buff *skb, void *phdr)
     /* [previous][next][first][last][top][bottom][index][help] */
1708 {
1709         return ip_fw_chk(phdr, skb->dev, ip_fw_fwd_chain, ip_fw_fwd_policy, 0);
1710 }
1711  
1712 struct firewall_ops ipfw_ops=
1713 {
1714         NULL,
1715         ipfw_forward_check,
1716         ipfw_input_check,
1717         ipfw_input_check,
1718         PF_INET,
1719         0       /* We don't even allow a fall through so we are last */
1720 };
1721 
1722 #endif
1723 
1724 void ip_fw_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1725 {
1726 #ifdef CONFIG_IP_ACCT
1727         proc_net_register(&(struct proc_dir_entry) {
1728                 PROC_NET_IPACCT, 7, "ip_acct",
1729                 S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
1730                 0, &proc_net_inode_operations,
1731                 ip_acct_procinfo
1732         });
1733 #endif
1734 #ifdef CONFIG_IP_FIREWALL
1735 
1736         if(register_firewall(PF_INET,&ipfw_ops)<0)
1737                 panic("Unable to register IP firewall.\n");
1738                 
1739         proc_net_register(&(struct proc_dir_entry) {
1740                 PROC_NET_IPFWBLK, 8, "ip_block",
1741                 S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
1742                 0, &proc_net_inode_operations,
1743                 ip_fw_blk_procinfo
1744         });
1745         proc_net_register(&(struct proc_dir_entry) {
1746                 PROC_NET_IPFWFWD, 10, "ip_forward",
1747                 S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
1748                 0, &proc_net_inode_operations,
1749                 ip_fw_fwd_procinfo
1750         });
1751 #endif
1752 #ifdef CONFIG_IP_MASQUERADE
1753         proc_net_register(&(struct proc_dir_entry) {
1754                 PROC_NET_IPMSQHST, 13, "ip_masquerade",
1755                 S_IFREG | S_IRUGO, 1, 0, 0,
1756                 0, &proc_net_inode_operations,
1757                 ip_msqhst_procinfo
1758         });
1759 #endif
1760 }

/* [previous][next][first][last][top][bottom][index][help] */