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

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