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

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