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

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