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

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

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