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

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