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. insert_in_chain
  12. append_to_chain
  13. del_from_chain
  14. check_ipfw_struct
  15. ip_acct_cnt
  16. ip_acct_ctl
  17. ip_fw_ctl
  18. ip_chain_procinfo
  19. ip_acct_procinfo
  20. ip_fw_in_procinfo
  21. ip_fw_out_procinfo
  22. ip_fw_fwd_procinfo
  23. ip_msqhst_procinfo
  24. ipfw_input_check
  25. ipfw_output_check
  26. ipfw_forward_check
  27. ip_fw_init

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

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