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

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