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

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