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                 tosand=0xFF;
 491                 tosxor=0x00;
 492 
 493         if(opt != 1) 
 494         {
 495                 if(policy&IP_FW_F_ACCEPT)
 496                         answer=(policy&IP_FW_F_MASQ)?FW_MASQUERADE:FW_ACCEPT;
 497                 else
 498                         if(policy&IP_FW_F_ICMPRPL)
 499                                 answer = FW_REJECT;
 500         }
 501 
 502         if (policy&IP_FW_F_ACCEPT) { /* Adjust priority and recompute checksum */
 503                 __u8 old_tos = ip->tos;
 504                 ip->tos = (old_tos & tosand) ^ tosxor;
 505                 if (ip->tos != old_tos)
 506                         ip_send_check(ip);
 507         }
 508 
 509         return answer;
 510 }
 511 
 512 #ifdef CONFIG_IP_MASQUERADE
 513 
 514 static void masq_expire(unsigned long data)
     /* [previous][next][first][last][top][bottom][index][help] */
 515 {
 516         struct ip_masq *ms = (struct ip_masq *)data;
 517         struct ip_masq *old,*cur;
 518         unsigned long flags;
 519 
 520 #ifdef DEBUG_MASQ
 521         printk("Masqueraded %s %lX:%X expired\n",
 522                         strProt[ms->protocol==IPPROTO_TCP],
 523                         ntohl(ms->src),ntohs(ms->sport));
 524 #endif
 525         
 526         save_flags(flags);
 527         cli();
 528 
 529         /* delete from list of hosts */
 530         old = NULL;
 531         cur = ip_msq_hosts;
 532         while (cur!=NULL) {
 533                 if (cur==ms) {
 534                         if (old==NULL) ip_msq_hosts = ms->next;
 535                         else old->next = ms->next;
 536                         kfree_s(ms,sizeof(*ms));
 537                         break;
 538                 }
 539                 old = cur;
 540                 cur=cur->next;
 541         }
 542         restore_flags(flags);
 543 }
 544 
 545 /*
 546  * Create a new masquerade list entry, also allocate an
 547  * unused mport, keeping the portnumber between the
 548  * given boundaries MASQ_BEGIN and MASQ_END.
 549  *
 550  * FIXME: possible deadlock if all free ports are exhausted! 
 551  */
 552 static struct ip_masq *alloc_masq_entry(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 553 {
 554         struct ip_masq *ms, *mst;
 555         unsigned long flags;
 556 
 557         ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), GFP_ATOMIC);
 558         if (ms==NULL) 
 559                 return NULL;
 560 
 561         memset(ms,0,sizeof(*ms));
 562         init_timer(&ms->timer);
 563         ms->timer.data     = (unsigned long)ms;
 564         ms->timer.function = masq_expire;
 565 
 566         save_flags(flags);
 567         cli();
 568         do 
 569         {
 570                 /* Try the next available port number */
 571                 ms->mport = htons(masq_port++);
 572                 if (masq_port==PORT_MASQ_END)
 573                         masq_port = PORT_MASQ_BEGIN;
 574 
 575                 /* Now hunt through the used ports to see if
 576                  * this port is in use... */
 577                 mst = ip_msq_hosts;
 578                 while (mst && mst->mport!=ms->mport)
 579                         mst = mst->next;
 580         }
 581         while (mst!=NULL); 
 582 
 583         /* add new entry in front of list to minimize lookup-time */
 584         ms->next  = ip_msq_hosts;
 585         ip_msq_hosts = ms;
 586         restore_flags(flags);
 587 
 588         return ms;
 589 }
 590 
 591 /*
 592  * When passing an FTP 'PORT' command, try to replace the IP
 593  * address with an newly assigned (masquereded) port on this
 594  * host, so the ftp-data connect FROM the site will succeed...
 595  *
 596  * Also, when the size of the packet changes, create an delta
 597  * offset, which will be added to every th->seq (and subtracted for
 598  * (th->acqseq) whose seq > init_seq.
 599  *
 600  * Not for the faint of heart!
 601  */
 602 
 603 static struct sk_buff *revamp(struct sk_buff *skb, struct device *dev, struct ip_masq *ftp)
     /* [previous][next][first][last][top][bottom][index][help] */
 604 {
 605         struct iphdr *iph = skb->h.iph;
 606         struct tcphdr *th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
 607         struct sk_buff *skb2;
 608         char *p, *data = (char *)&th[1];
 609         unsigned char p1,p2,p3,p4,p5,p6;
 610         unsigned long from;
 611         unsigned short port;
 612         struct ip_masq *ms;
 613         char buf[24];           /* xxx.xxx.xxx.xxx,ppp,ppp\000 */
 614         int diff;
 615         __u32 seq;
 616         
 617         /*
 618          * Adjust seq with delta-offset for all packets after the most recent resized PORT command
 619          * and with previous_delta offset for all packets before most recent resized PORT
 620          */
 621         
 622         /*
 623          * seq & seq_ack are in network byte order; need conversion before comparing
 624          */
 625         seq=ntohl(th->seq);
 626         if (ftp->delta || ftp->previous_delta)
 627         {
 628                 if(after(seq,ftp->init_seq) ) 
 629                 {
 630                         th->seq = htonl(seq + ftp->delta);
 631 #ifdef DEBUG_MASQ
 632                         printk("masq_revamp : added delta (%d) to seq\n",ftp->delta);
 633 #endif
 634                 }
 635                 else
 636                 {
 637                         th->seq = htonl(seq + ftp->previous_delta);
 638 #ifdef DEBUG_MASQ
 639                         printk("masq_revamp : added previous_delta (%d) to seq\n",ftp->previous_delta);
 640 #endif
 641                 }
 642         }
 643 
 644         while (skb->len - ((unsigned char *)data - skb->h.raw) > 18)
 645         {
 646                 if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) 
 647                 {
 648                         data ++;
 649                         continue;
 650                 }
 651                 p = data+5;
 652                 p1 = simple_strtoul(data+5,&data,10);
 653                 if (*data!=',')
 654                         continue;
 655                 p2 = simple_strtoul(data+1,&data,10);
 656                 if (*data!=',')
 657                         continue;
 658                 p3 = simple_strtoul(data+1,&data,10);
 659                 if (*data!=',')
 660                         continue;
 661                 p4 = simple_strtoul(data+1,&data,10);
 662                 if (*data!=',')
 663                         continue;
 664                 p5 = simple_strtoul(data+1,&data,10);
 665                 if (*data!=',')
 666                         continue;
 667                 p6 = simple_strtoul(data+1,&data,10);
 668                 if (*data!='\r' && *data!='\n')
 669                         continue;
 670 
 671                 from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
 672                 port = (p5<<8) | p6;
 673 #ifdef MASQ_DEBUG
 674                 printk("PORT %lX:%X detected\n",from,port);
 675 #endif  
 676                 /*
 677                  * Now create an masquerade entry for it
 678                  */
 679                 ms = alloc_masq_entry();
 680                 if (ms==NULL)
 681                         return skb;
 682                 ms->protocol = IPPROTO_TCP;
 683                 ms->src      = htonl(from);     /* derived from PORT cmd */
 684                 ms->sport    = htons(port);     /* derived from PORT cmd */
 685                 ms->dst      = iph->daddr;
 686                 /*
 687                  * Hardcoding 20 as dport is not always correct
 688                  * At least 1 Windows ftpd uses a random port number instead of 20
 689                  * Leave it undefined for now & wait for the first connection request to fill it out
 690                  */ 
 691                 ms->dport    = htons(FTP_DPORT_TBD);    /* ftp-data */
 692                 ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN;
 693                 add_timer(&ms->timer);
 694 
 695                 /*
 696                  * Replace the old PORT with the new one
 697                  */
 698                 from = ntohl(dev->pa_addr);
 699                 port = ntohs(ms->mport);
 700                 sprintf(buf,"%ld,%ld,%ld,%ld,%d,%d",
 701                         from>>24&255,from>>16&255,from>>8&255,from&255,
 702                         port>>8&255,port&255);
 703 
 704                 /*
 705                  * Calculate required delta-offset to keep TCP happy
 706                  */
 707                 
 708                 diff = strlen(buf) - (data-p);
 709                 
 710                 /*
 711                  *      No shift.
 712                  */
 713                  
 714                 if (diff==0) 
 715                 {
 716                         /*
 717                          * simple case, just replace the old PORT cmd
 718                          */
 719                         memcpy(p,buf,strlen(buf));
 720                         return skb;
 721                 }
 722  
 723                 /*
 724                  *      If the PORT command we have fiddled is the first, or is a
 725                  *      resend don't do the delta shift again. Doesn't work for
 726                  *      pathological cases, but we would need a history for that.
 727                  *      Also fails if you send 2^31 bytes of data down the link 
 728                  *      after the first port command.
 729                  *
 730                  *      FIXME: use ftp->init_seq_valid - 0 is a valid sequence.
 731                  */
 732                  
 733                 if(!ftp->init_seq || after(seq,ftp->init_seq) )
 734                 {
 735                         ftp->previous_delta=ftp->delta;
 736                         ftp->delta+=diff;
 737                         ftp->init_seq = seq;
 738                 }
 739                 
 740                 /*
 741                  * Sizes differ, make a copy
 742                  */
 743 #ifdef DEBUG_MASQ
 744                 printk("MASQUERADE: resizing needed for %d bytes (%ld)\n",diff, skb->len);
 745 #endif
 746                 skb2 = alloc_skb(MAX_HEADER + skb->len+diff, GFP_ATOMIC);
 747                 if (skb2 == NULL) {
 748                         printk("MASQUERADE: No memory available\n");
 749                         return skb;
 750                 }
 751                 skb2->free = skb->free;
 752                 skb_reserve(skb2,MAX_HEADER);
 753                 skb_put(skb2,skb->len + diff);
 754                 skb2->h.raw = skb2->data + (skb->h.raw - skb->data);
 755                 iph=skb2->h.iph;
 756                 /*
 757                  *      Mend the IP header too
 758                  */
 759                 iph->tot_len = htons(diff+ntohs(iph->tot_len));
 760                 iph->check = 0;
 761                 iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 762  
 763                 /*
 764                  *      Copy the packet data into the new buffer.
 765                  *      Thereby replacing the PORT cmd.
 766                  */
 767                 memcpy(skb2->data, skb->data, (p - (char *)skb->data));
 768                 memcpy(&skb2->data[(p - (char *)skb->data)], buf, strlen(buf));
 769                 memcpy(&skb2->data[(p - (char *)skb->data) + strlen(buf)], data,
 770                         skb->len - (data-(char *)skb->data));
 771 
 772                 /*
 773                  * Update tot_len field in ip header !
 774                  * Sequence numbers were allready modified in original packet
 775                  */
 776                 iph->tot_len = htons(skb->len + diff);
 777 
 778                 /*
 779                  * Problem, how to replace the new skb with old one,
 780                  * preferably inplace, so all the pointers in the
 781                  * calling tree keep ok :(
 782                  */
 783                 kfree_skb(skb, FREE_WRITE);
 784                 return skb2;
 785         }
 786         return skb;
 787 }
 788 
 789 static void recalc_check(struct udphdr *uh, unsigned long saddr,
     /* [previous][next][first][last][top][bottom][index][help] */
 790         unsigned long daddr, int len)
 791 {
 792         uh->check=0;
 793         uh->check=csum_tcpudp_magic(saddr,daddr,len,
 794                 IPPROTO_UDP, csum_partial((char *)uh,len,0));
 795         if(uh->check==0)
 796                 uh->check=0xFFFF;
 797 }
 798         
 799 void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 800 {
 801         struct sk_buff  *skb=*skb_ptr;
 802         struct iphdr    *iph = skb->h.iph;
 803         unsigned short  *portptr;
 804         struct ip_masq  *ms;
 805         int             size;
 806 
 807         /*
 808          * We can only masquerade protocols with ports...
 809          */
 810 
 811         if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
 812                 return;
 813  
 814         /*
 815          *      Now hunt the list to see if we have an old entry
 816          */
 817 
 818         portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]);
 819         ms = ip_msq_hosts;
 820 
 821 #ifdef DEBUG_MASQ
 822         printk("Outgoing %s %lX:%X -> %lX:%X\n",
 823                 strProt[iph->protocol==IPPROTO_TCP],
 824                 ntohl(iph->saddr), ntohs(portptr[0]),
 825                 ntohl(iph->daddr), ntohs(portptr[1]));
 826 #endif
 827         while (ms!=NULL) 
 828         {
 829                 if (iph->protocol == ms->protocol &&
 830                     iph->saddr == ms->src   && iph->daddr == ms->dst &&
 831                     portptr[0] == ms->sport && portptr[1] == ms->dport) 
 832                 {
 833                         del_timer(&ms->timer);
 834                         break;
 835                 }
 836                 ms = ms->next;
 837         }
 838 
 839         /*
 840          *      Nope, not found, create a new entry for it
 841          */
 842          
 843         if (ms==NULL) 
 844         {
 845                 ms = alloc_masq_entry();
 846                 if (ms==NULL) 
 847                 {
 848                         printk("MASQUERADE: no memory left !\n");
 849                         return;
 850                 }
 851                 ms->protocol = iph->protocol;
 852                 ms->src      = iph->saddr;
 853                 ms->dst      = iph->daddr;
 854                 ms->sport    = portptr[0];
 855                 ms->dport    = portptr[1];
 856         }
 857  
 858         /*
 859          *      Change the fragments origin
 860          */
 861          
 862         size = skb->len - ((unsigned char *)portptr - skb->h.raw);
 863         iph->saddr = dev->pa_addr; /* my own address */
 864         portptr[0] = ms->mport;
 865  
 866         /*
 867          *      Adjust packet accordingly to protocol
 868          */
 869          
 870         if (iph->protocol==IPPROTO_UDP) 
 871         {
 872                 ms->timer.expires = jiffies+MASQUERADE_EXPIRE_UDP;
 873                 recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
 874         }
 875         else 
 876         {
 877                 struct tcphdr *th;
 878                 if (portptr[1]==htons(21)) 
 879                 {
 880                         skb = revamp(*skb_ptr, dev, ms);
 881                         *skb_ptr = skb;
 882                         iph = skb->h.iph;
 883                         portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]);
 884                         size = skb->len - ((unsigned char *)portptr-skb->h.raw);
 885                 }
 886                 th = (struct tcphdr *)portptr;
 887  
 888                 /*
 889                  *      Timeout depends if FIN packet was seen
 890                  */
 891                 if (ms->sawfin || th->fin) 
 892                 {
 893                         ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN;
 894                         ms->sawfin = 1;
 895                 }
 896                 else ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP;
 897  
 898                 tcp_send_check(th,iph->saddr,iph->daddr,size,skb->sk);
 899         }
 900         add_timer(&ms->timer);
 901         ip_send_check(iph);
 902  
 903  #ifdef DEBUG_MASQ
 904         printk("O-routed from %lX:%X over %s\n",ntohl(dev->pa_addr),ntohs(ms->mport),dev->name);
 905  #endif
 906  }
 907  
 908  /*
 909   *     Check if it's an masqueraded port, look it up,
 910   *     and send it on it's way...
 911   *
 912   *     Better not have many hosts using the designated portrange
 913   *     as 'normal' ports, or you'll be spending lots of time in
 914   *     this function.
 915   */
 916 
 917 int ip_fw_demasquerade(struct sk_buff *skb_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 918 {
 919         struct iphdr    *iph = skb_ptr->h.iph;
 920         unsigned short  *portptr;
 921         struct ip_masq  *ms;
 922         struct tcphdr   *th = (struct tcphdr *)(skb_ptr->h.raw+(iph->ihl<<2));
 923  
 924         if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
 925                 return 0;
 926  
 927         portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]);
 928         if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
 929             ntohs(portptr[1]) > PORT_MASQ_END)
 930                 return 0;
 931  
 932 #ifdef DEBUG_MASQ
 933         printk("Incoming %s %lX:%X -> %lX:%X\n",
 934                 strProt[iph->protocol==IPPROTO_TCP],
 935                 ntohl(iph->saddr), ntohs(portptr[0]),
 936                 ntohl(iph->daddr), ntohs(portptr[1]));
 937 #endif
 938 
 939         /*
 940          * reroute to original host:port if found...
 941          *
 942          * NB. Cannot check destination address, just for the incoming port.
 943          * reason: archie.doc.ac.uk has 6 interfaces, you send to
 944          * phoenix and get a reply from any other interface(==dst)!
 945          *
 946          * [Only for UDP] - AC
 947          */
 948         ms = ip_msq_hosts;
 949         while (ms!=NULL) 
 950         {
 951                 if (iph->protocol==ms->protocol &&
 952                     (iph->saddr==ms->dst || iph->protocol==IPPROTO_UDP) && 
 953                     (ms->dport==htons(FTP_DPORT_TBD) || portptr[0]==ms->dport) &&
 954                     portptr[1]==ms->mport)
 955                 {
 956                 
 957                         int size = skb_ptr->len - ((unsigned char *)portptr - skb_ptr->h.raw);
 958                         iph->daddr = ms->src;
 959                         portptr[1] = ms->sport;
 960                         
 961                         if(ms->dport==htons(FTP_DPORT_TBD))
 962                         {
 963                                 ms->dport=portptr[0];
 964 #ifdef DEBUG_MASQ
 965                                 printk("demasq : Filled out dport entry (%d) based on initial connect attempt from FTP deamon\n",ntohs(ms->dport));
 966 #endif
 967                         }
 968 
 969                         /*
 970                          * Yug! adjust UDP/TCP and IP checksums
 971                          */
 972                         if (iph->protocol==IPPROTO_UDP)
 973                                 recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
 974                         else
 975                         {
 976                                 __u32 ack_seq;
 977                                 /*
 978                                  * Adjust ack_seq with delta-offset for
 979                                  * the packets AFTER most recent PORT command has caused a shift
 980                                  * for packets before most recent PORT command, use previous_delta
 981                                  */
 982 #ifdef DEBUG_MASQ
 983                                 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)));
 984 #endif
 985                                 ack_seq=ntohl(th->ack_seq);
 986                                 if (ms->delta || ms->previous_delta)
 987                                 {
 988                                         if(after(ack_seq,ms->init_seq))
 989                                         {
 990                                                 th->ack_seq = htonl(ack_seq-ms->delta);
 991 #ifdef DEBUG_MASQ
 992                                                 printk("demasq : substracted delta (%d) from ack_seq\n",ms->delta);
 993 #endif
 994                                         }
 995                                         else
 996                                         {
 997                                                 th->ack_seq = htonl(ack_seq-ms->previous_delta);
 998 #ifdef DEBUG_MASQ
 999                                                 printk("demasq : substracted previous_delta (%d) from ack_seq\n",ms->previous_delta);
1000 #endif
1001                                         }
1002                                 }
1003                                 tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb_ptr->sk);
1004                         }
1005                         ip_send_check(iph);
1006 #ifdef DEBUG_MASQ
1007                         printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1]));
1008 #endif
1009                         return 1;
1010                 }
1011                 ms = ms->next;
1012         }
1013  
1014         /* sorry, all this trouble for a no-hit :) */
1015         return 0;
1016 }
1017 #endif
1018   
1019 
1020 
1021 static void zero_fw_chain(struct ip_fw *chainptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1022 {
1023         struct ip_fw *ctmp=chainptr;
1024         while(ctmp) 
1025         {
1026                 ctmp->fw_pcnt=0L;
1027                 ctmp->fw_bcnt=0L;
1028                 ctmp=ctmp->fw_next;
1029         }
1030 }
1031 
1032 static void free_fw_chain(struct ip_fw *volatile* chainptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1033 {
1034         unsigned long flags;
1035         save_flags(flags);
1036         cli();
1037         while ( *chainptr != NULL ) 
1038         {
1039                 struct ip_fw *ftmp;
1040                 ftmp = *chainptr;
1041                 *chainptr = ftmp->fw_next;
1042                 kfree_s(ftmp,sizeof(*ftmp));
1043         }
1044         restore_flags(flags);
1045 }
1046 
1047 /* Volatiles to keep some of the compiler versions amused */
1048 
1049 static int insert_in_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1050 {
1051         struct ip_fw *ftmp;
1052         unsigned long flags;
1053 
1054         save_flags(flags);
1055 
1056         ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC );
1057         if ( ftmp == NULL ) 
1058         {
1059 #ifdef DEBUG_CONFIG_IP_FIREWALL
1060                 printk("ip_fw_ctl:  malloc said no\n");
1061 #endif
1062                 return( ENOMEM );
1063         }
1064 
1065         memcpy(ftmp, frwl, len);
1066         ftmp->fw_tosand |= 0x03;
1067         ftmp->fw_tosxor &= 0xFC;
1068         ftmp->fw_pcnt=0L;
1069         ftmp->fw_bcnt=0L;
1070 
1071         cli();
1072 
1073         ftmp->fw_next = *chainptr;
1074         *chainptr=ftmp;
1075         restore_flags(flags);
1076         return(0);
1077 }
1078 
1079 static int append_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1080 {
1081         struct ip_fw *ftmp;
1082         struct ip_fw *chtmp=NULL;
1083         struct ip_fw *volatile chtmp_prev=NULL;
1084         unsigned long flags;
1085 
1086         save_flags(flags);
1087 
1088         ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC );
1089         if ( ftmp == NULL ) 
1090         {
1091 #ifdef DEBUG_CONFIG_IP_FIREWALL
1092                 printk("ip_fw_ctl:  malloc said no\n");
1093 #endif
1094                 return( ENOMEM );
1095         }
1096 
1097         memcpy(ftmp, frwl, len);
1098         ftmp->fw_tosand |= 0x03;
1099         ftmp->fw_tosxor &= 0xFC;
1100         ftmp->fw_pcnt=0L;
1101         ftmp->fw_bcnt=0L;
1102 
1103         ftmp->fw_next = NULL;
1104 
1105         cli();
1106 
1107         chtmp_prev=NULL;
1108         for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->fw_next) 
1109                 chtmp_prev=chtmp;
1110         
1111         if (chtmp_prev)
1112                 chtmp_prev->fw_next=ftmp;
1113         else
1114                 *chainptr=ftmp;
1115         restore_flags(flags);
1116         return(0);
1117 }
1118 
1119 static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl)
     /* [previous][next][first][last][top][bottom][index][help] */
1120 {
1121         struct ip_fw    *ftmp,*ltmp;
1122         unsigned short  tport1,tport2,tmpnum;
1123         char            matches,was_found;
1124         unsigned long   flags;
1125 
1126         save_flags(flags);
1127         cli();
1128 
1129         ftmp=*chainptr;
1130 
1131         if ( ftmp == NULL ) 
1132         {
1133 #ifdef DEBUG_CONFIG_IP_FIREWALL
1134                 printk("ip_fw_ctl:  chain is empty\n");
1135 #endif
1136                 restore_flags(flags);
1137                 return( EINVAL );
1138         }
1139 
1140         ltmp=NULL;
1141         was_found=0;
1142 
1143         while( !was_found && ftmp != NULL )
1144         {
1145                 matches=1;
1146              if (ftmp->fw_src.s_addr!=frwl->fw_src.s_addr 
1147                      ||  ftmp->fw_dst.s_addr!=frwl->fw_dst.s_addr
1148                      ||  ftmp->fw_smsk.s_addr!=frwl->fw_smsk.s_addr
1149                      ||  ftmp->fw_dmsk.s_addr!=frwl->fw_dmsk.s_addr
1150                      ||  ftmp->fw_via.s_addr!=frwl->fw_via.s_addr
1151                      ||  ftmp->fw_flg!=frwl->fw_flg)
1152                         matches=0;
1153 
1154                 tport1=ftmp->fw_nsp+ftmp->fw_ndp;
1155                 tport2=frwl->fw_nsp+frwl->fw_ndp;
1156                 if (tport1!=tport2)
1157                         matches=0;
1158                 else if (tport1!=0)
1159                 {
1160                         for (tmpnum=0;tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS;tmpnum++)
1161                         if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum])
1162                                 matches=0;
1163                 }
1164                 if(matches)
1165                 {
1166                         was_found=1;
1167                         if (ltmp)
1168                         {
1169                                 ltmp->fw_next=ftmp->fw_next;
1170                                 kfree_s(ftmp,sizeof(*ftmp));
1171                                 ftmp=ltmp->fw_next;
1172                         }
1173                         else
1174                         {
1175                                 *chainptr=ftmp->fw_next; 
1176                                 kfree_s(ftmp,sizeof(*ftmp));
1177                                 ftmp=*chainptr;
1178                         }       
1179                 }
1180                 else
1181                 {
1182                         ltmp = ftmp;
1183                         ftmp = ftmp->fw_next;
1184                  }
1185         }
1186         restore_flags(flags);
1187         if (was_found)
1188                 return 0;
1189         else
1190                 return(EINVAL);
1191 }
1192 
1193 #endif  /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
1194 
1195 struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1196 {
1197 
1198         if ( len != sizeof(struct ip_fw) )
1199         {
1200 #ifdef DEBUG_CONFIG_IP_FIREWALL
1201                 printk("ip_fw_ctl: len=%d, want %d\n",len, sizeof(struct ip_fw));
1202 #endif
1203                 return(NULL);
1204         }
1205 
1206         if ( (frwl->fw_flg & ~IP_FW_F_MASK) != 0 )
1207         {
1208 #ifdef DEBUG_CONFIG_IP_FIREWALL
1209                 printk("ip_fw_ctl: undefined flag bits set (flags=%x)\n",
1210                         frwl->fw_flg);
1211 #endif
1212                 return(NULL);
1213         }
1214 
1215         if ( (frwl->fw_flg & IP_FW_F_SRNG) && frwl->fw_nsp < 2 ) 
1216         {
1217 #ifdef DEBUG_CONFIG_IP_FIREWALL
1218                 printk("ip_fw_ctl: src range set but fw_nsp=%d\n",
1219                         frwl->fw_nsp);
1220 #endif
1221                 return(NULL);
1222         }
1223 
1224         if ( (frwl->fw_flg & IP_FW_F_DRNG) && frwl->fw_ndp < 2 ) 
1225         {
1226 #ifdef DEBUG_CONFIG_IP_FIREWALL
1227                 printk("ip_fw_ctl: dst range set but fw_ndp=%d\n",
1228                         frwl->fw_ndp);
1229 #endif
1230                 return(NULL);
1231         }
1232 
1233         if ( frwl->fw_nsp + frwl->fw_ndp > IP_FW_MAX_PORTS ) 
1234         {
1235 #ifdef DEBUG_CONFIG_IP_FIREWALL
1236                 printk("ip_fw_ctl: too many ports (%d+%d)\n",
1237                         frwl->fw_nsp,frwl->fw_ndp);
1238 #endif
1239                 return(NULL);
1240         }
1241 
1242         return frwl;
1243 }
1244 
1245 
1246 
1247 
1248 #ifdef CONFIG_IP_ACCT
1249 
1250 #if 0
1251 void ip_acct_cnt(struct iphdr *iph, struct device *dev, struct ip_fw *f)
     /* [previous][next][first][last][top][bottom][index][help] */
1252 {
1253         (void) ip_fw_chk(iph, dev, f, 0, 1);
1254         return;
1255 }
1256 #endif
1257 
1258 int ip_acct_ctl(int stage, void *m, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1259 {
1260         if ( stage == IP_ACCT_FLUSH )
1261         {
1262                 free_fw_chain(&ip_acct_chain);
1263                 return(0);
1264         }  
1265         if ( stage == IP_ACCT_ZERO )
1266         {
1267                 zero_fw_chain(ip_acct_chain);
1268                 return(0);
1269         }
1270         if ( stage == IP_ACCT_INSERT || stage == IP_ACCT_APPEND ||
1271                                         stage == IP_ACCT_DELETE )
1272         {
1273                 struct ip_fw *frwl;
1274 
1275                 if (!(frwl=check_ipfw_struct(m,len)))
1276                         return (EINVAL);
1277 
1278                 switch (stage) 
1279                 {
1280                         case IP_ACCT_INSERT:
1281                                 return( insert_in_chain(&ip_acct_chain,frwl,len));
1282                         case IP_ACCT_APPEND:
1283                                 return( append_to_chain(&ip_acct_chain,frwl,len));
1284                         case IP_ACCT_DELETE:
1285                                 return( del_from_chain(&ip_acct_chain,frwl));
1286                         default:
1287                                 /*
1288                                  *      Should be panic but... (Why ??? - AC)
1289                                  */
1290 #ifdef DEBUG_CONFIG_IP_FIREWALL
1291                                 printk("ip_acct_ctl:  unknown request %d\n",stage);
1292 #endif
1293                                 return(EINVAL);
1294                 }
1295         }
1296 #ifdef DEBUG_CONFIG_IP_FIREWALL
1297         printk("ip_acct_ctl:  unknown request %d\n",stage);
1298 #endif
1299         return(EINVAL);
1300 }
1301 #endif
1302 
1303 #ifdef CONFIG_IP_FIREWALL
1304 int ip_fw_ctl(int stage, void *m, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1305 {
1306         int ret, cmd, fwtype;
1307 
1308         cmd = stage & IP_FW_COMMAND;
1309         fwtype = (stage & IP_FW_TYPE) >> IP_FW_SHIFT;
1310 
1311         if ( cmd == IP_FW_FLUSH )
1312         {
1313                 free_fw_chain(chains[fwtype]);
1314                 return(0);
1315         }  
1316 
1317         if ( cmd == IP_FW_ZERO )
1318         {
1319                 zero_fw_chain(*chains[fwtype]);
1320                 return(0);
1321         }  
1322 
1323         if ( cmd == IP_FW_POLICY )
1324         {
1325                 int *tmp_policy_ptr;
1326                 tmp_policy_ptr=(int *)m;
1327                 *policies[fwtype] = *tmp_policy_ptr;
1328                 return 0;
1329         }
1330 
1331         if ( cmd == IP_FW_CHECK )
1332         {
1333                 struct device viadev;
1334                 struct ip_fwpkt *ipfwp;
1335                 struct iphdr *ip;
1336 
1337                 if ( len < sizeof(struct ip_fwpkt) )
1338                 {
1339 #ifdef DEBUG_CONFIG_IP_FIREWALL
1340                         printk("ip_fw_ctl: length=%d, expected %d\n",
1341                                 len, sizeof(struct ip_fwpkt));
1342 #endif
1343                         return( EINVAL );
1344                 }
1345 
1346                 ipfwp = (struct ip_fwpkt *)m;
1347                 ip = &(ipfwp->fwp_iph);
1348 
1349                 if ( ip->ihl != sizeof(struct iphdr) / sizeof(int))
1350                 {
1351 #ifdef DEBUG_CONFIG_IP_FIREWALL
1352                         printk("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl,
1353                                         sizeof(struct iphdr)/sizeof(int));
1354 #endif
1355                         return(EINVAL);
1356                 }
1357 
1358                 viadev.pa_addr = ipfwp->fwp_via.s_addr;
1359 
1360                 if ((ret = ip_fw_chk(ip, &viadev, *chains[fwtype],
1361                                 *policies[fwtype], 2)) == FW_ACCEPT)
1362                         return(0);
1363                 else if (ret == FW_MASQUERADE)  
1364                         return(ECONNRESET);
1365                 else if (ret == FW_REJECT)      
1366                         return(ECONNREFUSED);
1367                 else /* ret == FW_BLOCK */
1368                         return(ETIMEDOUT);
1369         }
1370 
1371 /*
1372  *      Here we really working hard-adding new elements
1373  *      to blocking/forwarding chains or deleting 'em
1374  */
1375 
1376         if ( cmd == IP_FW_INSERT || cmd == IP_FW_APPEND || cmd == IP_FW_DELETE )
1377         {
1378                 struct ip_fw *frwl;
1379                 int fwtype;
1380 
1381                 frwl=check_ipfw_struct(m,len);
1382                 if (frwl==NULL)
1383                         return (EINVAL);
1384                 fwtype = (stage & IP_FW_TYPE) >> IP_FW_SHIFT;
1385                 
1386                 switch (cmd) 
1387                 {
1388                         case IP_FW_INSERT:
1389                                 return(insert_in_chain(chains[fwtype],frwl,len));
1390                         case IP_FW_APPEND:
1391                                 return(append_to_chain(chains[fwtype],frwl,len));
1392                         case IP_FW_DELETE:
1393                                 return(del_from_chain(chains[fwtype],frwl));
1394                         default:
1395                         /*
1396                          *      Should be panic but... (Why are BSD people panic obsessed ??)
1397                          */
1398 #ifdef DEBUG_CONFIG_IP_FIREWALL
1399                                 printk("ip_fw_ctl:  unknown request %d\n",stage);
1400 #endif
1401                                 return(EINVAL);
1402                 }
1403         } 
1404 
1405 #ifdef DEBUG_CONFIG_IP_FIREWALL
1406         printk("ip_fw_ctl:  unknown request %d\n",stage);
1407 #endif
1408         return(EINVAL);
1409 }
1410 #endif /* CONFIG_IP_FIREWALL */
1411 
1412 #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
1413 
1414 static int ip_chain_procinfo(int stage, char *buffer, char **start,
     /* [previous][next][first][last][top][bottom][index][help] */
1415                              off_t offset, int length, int reset)
1416 {
1417         off_t pos=0, begin=0;
1418         struct ip_fw *i;
1419         unsigned long flags;
1420         int len, p;
1421         
1422 
1423         switch(stage)
1424         {
1425 #ifdef CONFIG_IP_FIREWALL
1426                 case IP_FW_IN:
1427                         i = ip_fw_in_chain;
1428                         len=sprintf(buffer, "IP firewall input rules, default %d\n",
1429                                 ip_fw_in_policy);
1430                         break;
1431                 case IP_FW_OUT:
1432                         i = ip_fw_out_chain;
1433                         len=sprintf(buffer, "IP firewall output rules, default %d\n",
1434                                 ip_fw_out_policy);
1435                         break;
1436                 case IP_FW_FWD:
1437                         i = ip_fw_fwd_chain;
1438                         len=sprintf(buffer, "IP firewall forward rules, default %d\n",
1439                                 ip_fw_fwd_policy);
1440                         break;
1441 #endif
1442 #ifdef CONFIG_IP_ACCT
1443                 case IP_FW_ACCT:
1444                         i = ip_acct_chain;
1445                         len=sprintf(buffer,"IP accounting rules\n");
1446                         break;
1447 #endif
1448                 default:
1449                         /* this should never be reached, but safety first... */
1450                         i = NULL;
1451                         len=0;
1452                         break;
1453         }
1454 
1455         save_flags(flags);
1456         cli();
1457         
1458         while(i!=NULL)
1459         {
1460                 len+=sprintf(buffer+len,"%08lX/%08lX->%08lX/%08lX %08lX %X ",
1461                         ntohl(i->fw_src.s_addr),ntohl(i->fw_smsk.s_addr),
1462                         ntohl(i->fw_dst.s_addr),ntohl(i->fw_dmsk.s_addr),
1463                         ntohl(i->fw_via.s_addr),i->fw_flg);
1464                 len+=sprintf(buffer+len,"%u %u %-9lu %-9lu",
1465                         i->fw_nsp,i->fw_ndp, i->fw_pcnt,i->fw_bcnt);
1466                 for (p = 0; p < IP_FW_MAX_PORTS; p++)
1467                         len+=sprintf(buffer+len, " %u", i->fw_pts[p]);
1468                 len+=sprintf(buffer+len, " A%02X X%02X", i->fw_tosand, i->fw_tosxor);
1469                 buffer[len++]='\n';
1470                 buffer[len]='\0';
1471                 pos=begin+len;
1472                 if(pos<offset)
1473                 {
1474                         len=0;
1475                         begin=pos;
1476                 }
1477                 else if(reset)
1478                 {
1479                         /* This needs to be done at this specific place! */
1480                         i->fw_pcnt=0L;
1481                         i->fw_bcnt=0L;
1482                 }
1483                 if(pos>offset+length)
1484                         break;
1485                 i=i->fw_next;
1486         }
1487         restore_flags(flags);
1488         *start=buffer+(offset-begin);
1489         len-=(offset-begin);
1490         if(len>length)
1491                 len=length;     
1492         return len;
1493 }
1494 #endif
1495 
1496 #ifdef CONFIG_IP_ACCT
1497 
1498 static int ip_acct_procinfo(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
1499                             int length, int reset)
1500 {
1501         return ip_chain_procinfo(IP_FW_ACCT, buffer,start, offset,length,
1502                                  reset);
1503 }
1504 
1505 #endif
1506 
1507 #ifdef CONFIG_IP_FIREWALL
1508 
1509 static int ip_fw_in_procinfo(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
1510                               int length, int reset)
1511 {
1512         return ip_chain_procinfo(IP_FW_IN, buffer,start,offset,length,
1513                                  reset);
1514 }
1515 
1516 static int ip_fw_out_procinfo(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
1517                               int length, int reset)
1518 {
1519         return ip_chain_procinfo(IP_FW_OUT, buffer,start,offset,length,
1520                                  reset);
1521 }
1522 
1523 static int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
1524                               int length, int reset)
1525 {
1526         return ip_chain_procinfo(IP_FW_FWD, buffer,start,offset,length,
1527                                  reset);
1528 }
1529 #endif
1530 
1531 #ifdef CONFIG_IP_MASQUERADE
1532 
1533 static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
1534                               int length, int unused)
1535 {
1536         off_t pos=0, begin=0;
1537         struct ip_masq *ms;
1538         unsigned long flags;
1539         int len=0;
1540         
1541         len=sprintf(buffer,"Prc FromIP   FPrt ToIP     TPrt Masq Init-seq  Delta PDelta Expires\n"); 
1542         save_flags(flags);
1543         cli();
1544         
1545         ms=ip_msq_hosts;
1546         while (ms!=NULL) 
1547         {
1548                 int timer_active = del_timer(&ms->timer);
1549                 if (!timer_active)
1550                         ms->timer.expires = jiffies;
1551                 len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %lu\n",
1552                         strProt[ms->protocol==IPPROTO_TCP],
1553                         ntohl(ms->src),ntohs(ms->sport),
1554                         ntohl(ms->dst),ntohs(ms->dport),
1555                         ntohs(ms->mport),
1556                         ms->init_seq,ms->delta,ms->previous_delta,ms->timer.expires-jiffies);
1557                 if (timer_active)
1558                         add_timer(&ms->timer);
1559 
1560                 pos=begin+len;
1561                 if(pos<offset) 
1562                 {
1563                         len=0;
1564                         begin=pos;
1565                 }
1566                 if(pos>offset+length)
1567                         break;
1568                 ms=ms->next;
1569         }
1570         restore_flags(flags);
1571         *start=buffer+(offset-begin);
1572         len-=(offset-begin);
1573         if(len>length)
1574                 len=length;
1575         return len;
1576 }
1577   
1578 #endif
1579 
1580 #ifdef CONFIG_IP_FIREWALL
1581 /*
1582  *      Interface to the generic firewall chains.
1583  */
1584  
1585 int ipfw_input_check(struct firewall_ops *this, int pf, struct sk_buff *skb, void *phdr)
     /* [previous][next][first][last][top][bottom][index][help] */
1586 {
1587         return ip_fw_chk(phdr, skb->dev, ip_fw_in_chain, ip_fw_in_policy, 0);
1588 }
1589 
1590 int ipfw_output_check(struct firewall_ops *this, int pf, struct sk_buff *skb, void *phdr)
     /* [previous][next][first][last][top][bottom][index][help] */
1591 {
1592         return ip_fw_chk(phdr, skb->dev, ip_fw_out_chain, ip_fw_out_policy, 0);
1593 }
1594 
1595 int ipfw_forward_check(struct firewall_ops *this, int pf, struct sk_buff *skb, void *phdr)
     /* [previous][next][first][last][top][bottom][index][help] */
1596 {
1597         return ip_fw_chk(phdr, skb->dev, ip_fw_fwd_chain, ip_fw_fwd_policy, 0);
1598 }
1599  
1600 struct firewall_ops ipfw_ops=
1601 {
1602         NULL,
1603         ipfw_forward_check,
1604         ipfw_input_check,
1605         ipfw_output_check,
1606         PF_INET,
1607         0       /* We don't even allow a fall through so we are last */
1608 };
1609 
1610 #endif
1611 
1612 void ip_fw_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1613 {
1614 #ifdef CONFIG_IP_ACCT
1615         proc_net_register(&(struct proc_dir_entry) {
1616                 PROC_NET_IPACCT, 7, "ip_acct",
1617                 S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
1618                 0, &proc_net_inode_operations,
1619                 ip_acct_procinfo
1620         });
1621 #endif
1622 #ifdef CONFIG_IP_FIREWALL
1623 
1624         if(register_firewall(PF_INET,&ipfw_ops)<0)
1625                 panic("Unable to register IP firewall.\n");
1626                 
1627         proc_net_register(&(struct proc_dir_entry) {
1628                 PROC_NET_IPFWIN, 8, "ip_input",
1629                 S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
1630                 0, &proc_net_inode_operations,
1631                 ip_fw_in_procinfo
1632         });
1633         proc_net_register(&(struct proc_dir_entry) {
1634                 PROC_NET_IPFWOUT, 9, "ip_output",
1635                 S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
1636                 0, &proc_net_inode_operations,
1637                 ip_fw_out_procinfo
1638         });
1639         proc_net_register(&(struct proc_dir_entry) {
1640                 PROC_NET_IPFWFWD, 10, "ip_forward",
1641                 S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
1642                 0, &proc_net_inode_operations,
1643                 ip_fw_fwd_procinfo
1644         });
1645 #endif
1646 #ifdef CONFIG_IP_MASQUERADE
1647         proc_net_register(&(struct proc_dir_entry) {
1648                 PROC_NET_IPMSQHST, 13, "ip_masquerade",
1649                 S_IFREG | S_IRUGO, 1, 0, 0,
1650                 0, &proc_net_inode_operations,
1651                 ip_msqhst_procinfo
1652         });
1653 #endif
1654 }

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