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. zero_fw_chain
  4. free_fw_chain
  5. insert_in_chain
  6. append_to_chain
  7. del_from_chain
  8. check_ipfw_struct
  9. ip_acct_cnt
  10. ip_acct_ctl
  11. ip_fw_ctl
  12. ip_chain_procinfo
  13. ip_acct_procinfo
  14. ip_fw_in_procinfo
  15. ip_fw_out_procinfo
  16. ip_fw_fwd_procinfo
  17. ipfw_input_check
  18. ipfw_output_check
  19. ipfw_forward_check
  20. ipfw_device_event
  21. 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  *
  38  * Masquerading functionality
  39  *
  40  * Copyright (c) 1994 Pauline Middelink
  41  *
  42  * The pieces which added masquerading functionality are totally
  43  * my responsibility and have nothing to with the original authors
  44  * copyright or doing.
  45  *
  46  * Parts distributed under GPL.
  47  *
  48  * Fixes:
  49  *      Pauline Middelink       :       Added masquerading.
  50  *      Alan Cox                :       Fixed an error in the merge.
  51  *      Thomas Quinot           :       Fixed port spoofing.
  52  *      Alan Cox                :       Cleaned up retransmits in spoofing.
  53  *      Alan Cox                :       Cleaned up length setting.
  54  *      Wouter Gadeyne          :       Fixed masquerading support of ftp PORT commands
  55  *
  56  *      Juan Jose Ciarlante     :       Masquerading code moved to ip_masq.c
  57  *
  58  *      All the real work was done by .....
  59  *
  60  */
  61 
  62 
  63 /*
  64  * Copyright (c) 1993 Daniel Boulet
  65  * Copyright (c) 1994 Ugen J.S.Antsilevich
  66  *
  67  * Redistribution and use in source forms, with and without modification,
  68  * are permitted provided that this entire comment appears intact.
  69  *
  70  * Redistribution in binary form may occur without any restrictions.
  71  * Obviously, it would be nice if you gave credit where credit is due
  72  * but requiring it would be too onerous.
  73  *
  74  * This software is provided ``AS IS'' without any warranties of any kind.
  75  */
  76 
  77 #include <linux/config.h>
  78 #include <asm/segment.h>
  79 #include <asm/system.h>
  80 #include <linux/types.h>
  81 #include <linux/kernel.h>
  82 #include <linux/sched.h>
  83 #include <linux/string.h>
  84 #include <linux/errno.h>
  85 #include <linux/config.h>
  86 
  87 #include <linux/socket.h>
  88 #include <linux/sockios.h>
  89 #include <linux/in.h>
  90 #include <linux/inet.h>
  91 #include <linux/netdevice.h>
  92 #include <linux/icmp.h>
  93 #include <linux/udp.h>
  94 #include <net/ip.h>
  95 #include <net/protocol.h>
  96 #include <net/route.h>
  97 #include <net/tcp.h>
  98 #include <net/udp.h>
  99 #include <net/sock.h>
 100 #include <net/icmp.h>
 101 #include <linux/firewall.h>
 102 #include <linux/ip_fw.h>
 103 
 104 #ifdef CONFIG_IP_MASQUERADE
 105 #include <net/ip_masq.h>
 106 #endif
 107 
 108 #include <net/checksum.h>
 109 #include <linux/proc_fs.h>
 110 #include <linux/stat.h>
 111 
 112 /*
 113  *      Implement IP packet firewall
 114  */
 115 
 116 #ifdef CONFIG_IP_FIREWALL_DEBUG 
 117 #define dprintf1(a)             printk(a)
 118 #define dprintf2(a1,a2)         printk(a1,a2)
 119 #define dprintf3(a1,a2,a3)      printk(a1,a2,a3)
 120 #define dprintf4(a1,a2,a3,a4)   printk(a1,a2,a3,a4)
 121 #else
 122 #define dprintf1(a)     
 123 #define dprintf2(a1,a2)
 124 #define dprintf3(a1,a2,a3)
 125 #define dprintf4(a1,a2,a3,a4)
 126 #endif
 127 
 128 #define print_ip(a)      printk("%ld.%ld.%ld.%ld",(ntohl(a)>>24)&0xFF,\
 129                                               (ntohl(a)>>16)&0xFF,\
 130                                               (ntohl(a)>>8)&0xFF,\
 131                                               (ntohl(a))&0xFF);
 132 
 133 #ifdef CONFIG_IP_FIREWALL_DEBUG
 134 #define dprint_ip(a)    print_ip(a)
 135 #else
 136 #define dprint_ip(a)    
 137 #endif
 138 
 139 #if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
 140 
 141 struct ip_fw *ip_fw_fwd_chain;
 142 struct ip_fw *ip_fw_in_chain;
 143 struct ip_fw *ip_fw_out_chain;
 144 struct ip_fw *ip_acct_chain;
 145 
 146 static struct ip_fw **chains[] =
 147         {&ip_fw_fwd_chain, &ip_fw_in_chain, &ip_fw_out_chain, &ip_acct_chain};
 148 
 149 int ip_fw_fwd_policy=IP_FW_F_ACCEPT;
 150 int ip_fw_in_policy=IP_FW_F_ACCEPT;
 151 int ip_fw_out_policy=IP_FW_F_ACCEPT;
 152 
 153 static int *policies[] =
 154         {&ip_fw_fwd_policy, &ip_fw_in_policy, &ip_fw_out_policy};
 155 
 156 #endif
 157 
 158 /*
 159  *      Returns 1 if the port is matched by the vector, 0 otherwise
 160  */
 161 
 162 extern inline int port_match(unsigned short *portptr,int nports,unsigned short port,int range_flag)
     /* [previous][next][first][last][top][bottom][index][help] */
 163 {
 164         if (!nports)
 165                 return 1;
 166         if ( range_flag ) 
 167         {
 168                 if ( portptr[0] <= port && port <= portptr[1] ) 
 169                 {
 170                         return( 1 );
 171                 }
 172                 nports -= 2;
 173                 portptr += 2;
 174         }
 175         while ( nports-- > 0 ) 
 176         {
 177                 if ( *portptr++ == port ) 
 178                 {
 179                         return( 1 );
 180                 }
 181         }
 182         return(0);
 183 }
 184 
 185 #if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
 186 
 187 
 188 /*
 189  *      Returns 0 if packet should be dropped, 1 if it should be accepted,
 190  *      and -1 if an ICMP host unreachable packet should be sent.
 191  *      Also does accounting so you can feed it the accounting chain.
 192  *      If opt is set to 1, it means that we do this for accounting
 193  *      purposes (searches all entries and handles fragments different).
 194  *      If opt is set to 2, it doesn't count a matching packet, which
 195  *      is used when calling this for checking purposes (IP_FW_CHK_*).
 196  */
 197 
 198 
 199 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] */
 200 {
 201         struct ip_fw *f;
 202         struct tcphdr           *tcp=(struct tcphdr *)((unsigned long *)ip+ip->ihl);
 203         struct udphdr           *udp=(struct udphdr *)((unsigned long *)ip+ip->ihl);
 204         struct icmphdr          *icmp=(struct icmphdr *)((unsigned long *)ip+ip->ihl);
 205         __u32                   src, dst;
 206         __u16                   src_port=0xFFFF, dst_port=0xFFFF, icmp_type=0xFF;
 207         unsigned short          f_prt=0, prt;
 208         char                    notcpsyn=1, notcpack=1, match;
 209         unsigned short          offset;
 210         int                     answer;
 211         unsigned char           tosand, tosxor;
 212 
 213         /*
 214          *      If the chain is empty follow policy. The BSD one
 215          *      accepts anything giving you a time window while
 216          *      flushing and rebuilding the tables.
 217          */
 218          
 219         src = ip->saddr;
 220         dst = ip->daddr;
 221 
 222         /* 
 223          *      This way we handle fragmented packets.
 224          *      we ignore all fragments but the first one
 225          *      so the whole packet can't be reassembled.
 226          *      This way we relay on the full info which
 227          *      stored only in first packet.
 228          *
 229          *      Note that this theoretically allows partial packet
 230          *      spoofing. Not very dangerous but paranoid people may
 231          *      wish to play with this. It also allows the so called
 232          *      "fragment bomb" denial of service attack on some types
 233          *      of system.
 234          */
 235 
 236         offset = ntohs(ip->frag_off) & IP_OFFSET;
 237         
 238         /*
 239          *      Don't allow a fragment of TCP 8 bytes in. Nobody
 240          *      normal causes this. Its a cracker trying to break
 241          *      in by doing a flag overwrite to pass the direction
 242          *      checks.
 243          */
 244          
 245         if (offset == 1 && ip->protocol == IPPROTO_TCP)
 246                 return FW_BLOCK;
 247                 
 248         if (offset!=0 && (opt != 1) && (ip->protocol == IPPROTO_TCP ||
 249                         ip->protocol == IPPROTO_UDP || ip->protocol == IPPROTO_ICMP))
 250                 return FW_ACCEPT;
 251                 
 252         /*
 253          *       Header fragment for TCP is too small to check the bits.
 254          */
 255          
 256         if(ip->protocol==IPPROTO_TCP && (ip->ihl<<2)+16 > ntohs(ip->tot_len))
 257                 return FW_BLOCK;
 258         
 259         /*
 260          *      Too short.
 261          */
 262          
 263         else if(ntohs(ip->tot_len)<8+(ip->ihl<<2))
 264                 return FW_BLOCK;
 265                 
 266         src = ip->saddr;
 267         dst = ip->daddr;
 268 
 269         /*
 270          *      If we got interface from which packet came
 271          *      we can use the address directly. This is unlike
 272          *      4.4BSD derived systems that have an address chain
 273          *      per device. We have a device per address with dummy
 274          *      devices instead.
 275          */
 276          
 277         dprintf1("Packet ");
 278         switch(ip->protocol) 
 279         {
 280                 case IPPROTO_TCP:
 281                         dprintf1("TCP ");
 282                         /* ports stay 0xFFFF if it is not the first fragment */
 283                         if (!offset) {
 284                                 src_port=ntohs(tcp->source);
 285                                 dst_port=ntohs(tcp->dest);
 286                                 if(tcp->ack)
 287                                         /* We *DO* have ACK, value FALSE */
 288                                         notcpack=0;
 289                                 if(tcp->syn && notcpack)
 290                                         /* We *DO* have SYN, value FALSE */
 291                                         notcpsyn=0;
 292                         }
 293                         prt=IP_FW_F_TCP;
 294                         break;
 295                 case IPPROTO_UDP:
 296                         dprintf1("UDP ");
 297                         /* ports stay 0xFFFF if it is not the first fragment */
 298                         if (!offset) {
 299                                 src_port=ntohs(udp->source);
 300                                 dst_port=ntohs(udp->dest);
 301                         }
 302                         prt=IP_FW_F_UDP;
 303                         break;
 304                 case IPPROTO_ICMP:
 305                         /* icmp_type stays 255 if it is not the first fragment */
 306                         if (!offset)
 307                                 icmp_type=(__u16)(icmp->type);
 308                         dprintf2("ICMP:%d ",icmp_type);
 309                         prt=IP_FW_F_ICMP;
 310                         break;
 311                 default:
 312                         dprintf2("p=%d ",ip->protocol);
 313                         prt=IP_FW_F_ALL;
 314                         break;
 315         }
 316 #ifdef CONFIG_IP_FIREWALL_DEBUG
 317         dprint_ip(ip->saddr);
 318         
 319         if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
 320                 /* This will print 65535 when it is not the first fragment! */
 321                 dprintf2(":%d ", src_port);
 322         dprint_ip(ip->daddr);
 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 ",dst_port);
 326         dprintf1("\n");
 327 #endif  
 328 
 329         for (f=chain;f;f=f->fw_next) 
 330         {
 331                 /*
 332                  *      This is a bit simpler as we don't have to walk
 333                  *      an interface chain as you do in BSD - same logic
 334                  *      however.
 335                  */
 336 
 337                 /*
 338                  *      Match can become 0x01 (a "normal" match was found),
 339                  *      0x02 (a reverse match was found), and 0x03 (the
 340                  *      IP addresses match in both directions).
 341                  *      Now we know in which direction(s) we should look
 342                  *      for a match for the TCP/UDP ports.  Both directions
 343                  *      might match (e.g., when both addresses are on the
 344                  *      same network for which an address/mask is given), but
 345                  *      the ports might only match in one direction.
 346                  *      This was obviously wrong in the original BSD code.
 347                  */
 348                 match = 0x00;
 349 
 350                 if ((src&f->fw_smsk.s_addr)==f->fw_src.s_addr
 351                 &&  (dst&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
 352                         /* normal direction */
 353                         match |= 0x01;
 354 
 355                 if ((f->fw_flg & IP_FW_F_BIDIR) &&
 356                     (dst&f->fw_smsk.s_addr)==f->fw_src.s_addr
 357                 &&  (src&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
 358                         /* reverse direction */
 359                         match |= 0x02;
 360 
 361                 if (match)
 362                 {
 363                         /*
 364                          *      Look for a VIA address match 
 365                          */
 366                         if(f->fw_via.s_addr && rif)
 367                         {
 368                                 if(rif->pa_addr!=f->fw_via.s_addr)
 369                                         continue;       /* Mismatch */
 370                         }
 371 
 372                         /*
 373                          *      Look for a VIA device match 
 374                          */
 375                         if(f->fw_viadev)
 376                         {
 377                                 if(rif!=f->fw_viadev)
 378                                         continue;       /* Mismatch */
 379                         }
 380 
 381                         /*
 382                          *      Drop through - this is a match
 383                          */
 384                 }
 385                 else
 386                         continue;
 387 
 388                 /*
 389                  *      Ok the chain addresses match.
 390                  */
 391 
 392                 f_prt=f->fw_flg&IP_FW_F_KIND;
 393                 if (f_prt!=IP_FW_F_ALL) 
 394                 {
 395                         /*
 396                          * This is actually buggy as if you set ACK/SYN flags
 397                          * on UDP or ICMP firewall it will never work,but 
 398                          * actually it is a concern of software which sets
 399                          * firewall entries.
 400                          */
 401                          
 402                         if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn)
 403                                 continue;
 404 
 405                         if((f->fw_flg&IP_FW_F_TCPACK) && notcpack)
 406                                 continue;
 407 
 408                         /*
 409                          *      Specific firewall - packet's protocol
 410                          *      must match firewall's.
 411                          */
 412 
 413                         if(prt!=f_prt)
 414                                 continue;
 415                                 
 416                         if((prt==IP_FW_F_ICMP &&
 417                                 ! port_match(&f->fw_pts[0], f->fw_nsp,
 418                                         icmp_type,f->fw_flg&IP_FW_F_SRNG)) ||
 419                             !(prt==IP_FW_F_ICMP || ((match & 0x01) &&
 420                                 port_match(&f->fw_pts[0], f->fw_nsp, src_port,
 421                                         f->fw_flg&IP_FW_F_SRNG) &&
 422                                 port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port,
 423                                         f->fw_flg&IP_FW_F_DRNG)) || ((match & 0x02) &&
 424                                 port_match(&f->fw_pts[0], f->fw_nsp, dst_port,
 425                                         f->fw_flg&IP_FW_F_SRNG) &&
 426                                 port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, src_port,
 427                                         f->fw_flg&IP_FW_F_DRNG))))
 428                         {
 429                                 continue;
 430                         }
 431                 }
 432 #ifdef CONFIG_IP_FIREWALL_VERBOSE
 433                 /*
 434                  * VERY ugly piece of code which actually
 435                  * makes kernel printf for matching packets...
 436                  */
 437 
 438                 if (f->fw_flg & IP_FW_F_PRN)
 439                 {
 440                         if(opt != 1) {
 441                                 if(f->fw_flg&IP_FW_F_ACCEPT) {
 442                                         if(f->fw_flg&IP_FW_F_MASQ)
 443                                                 printk("masq ");
 444                                         else
 445                                                 printk("acc  ");
 446                                 } else if(f->fw_flg&IP_FW_F_ICMPRPL)
 447                                         printk("rej  ");
 448                                 else
 449                                         printk("deny ");
 450                         }
 451                         if (rif)
 452                                 printk("%s ", rif->name);
 453                         switch(ip->protocol)
 454                         {
 455                                 case IPPROTO_TCP:
 456                                         printk("TCP ");
 457                                         break;
 458                                 case IPPROTO_UDP:
 459                                         printk("UDP ");
 460                                         break;
 461                                 case IPPROTO_ICMP:
 462                                         printk("ICMP:%d ", icmp_type);
 463                                         break;
 464                                 default:
 465                                         printk("p=%d ",ip->protocol);
 466                                         break;
 467                         }
 468                         print_ip(ip->saddr);
 469                         if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
 470                                 printk(":%d", src_port);
 471                         printk(" ");
 472                         print_ip(ip->daddr);
 473                         if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
 474                                 printk(":%d",dst_port);
 475                         printk("\n");
 476                 }
 477 #endif          
 478                 if (opt != 2) {
 479                         f->fw_bcnt+=ntohs(ip->tot_len);
 480                         f->fw_pcnt++;
 481                 }
 482                 if (opt != 1)
 483                         break;
 484         } /* Loop */
 485         
 486         if (opt != 1) {
 487 
 488                 /*
 489                  * We rely on policy defined in the rejecting entry or, if no match
 490                  * was found, we rely on the general policy variable for this type
 491                  * of firewall.
 492                  */
 493 
 494                 if (f!=NULL) {
 495                         policy=f->fw_flg;
 496                         tosand=f->fw_tosand;
 497                         tosxor=f->fw_tosxor;
 498                 } else {
 499                         tosand=0xFF;
 500                         tosxor=0x00;
 501                 }
 502 
 503                 if (policy&IP_FW_F_ACCEPT) {
 504                         /* Adjust priority and recompute checksum */
 505                         __u8 old_tos = ip->tos;
 506                         ip->tos = (old_tos & tosand) ^ tosxor;
 507                         if (ip->tos != old_tos)
 508                                 ip_send_check(ip);
 509                         answer=(policy&IP_FW_F_MASQ)?FW_MASQUERADE:FW_ACCEPT;
 510                 } else if(policy&IP_FW_F_ICMPRPL)
 511                         answer = FW_REJECT;
 512                 else
 513                         answer = FW_BLOCK;
 514 
 515                 return answer;
 516         } else
 517                 /* we're doing accounting, always ok */
 518                 return 0;
 519 }
 520 
 521 
 522 static void zero_fw_chain(struct ip_fw *chainptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 523 {
 524         struct ip_fw *ctmp=chainptr;
 525         while(ctmp) 
 526         {
 527                 ctmp->fw_pcnt=0L;
 528                 ctmp->fw_bcnt=0L;
 529                 ctmp=ctmp->fw_next;
 530         }
 531 }
 532 
 533 static void free_fw_chain(struct ip_fw *volatile* chainptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 534 {
 535         unsigned long flags;
 536         save_flags(flags);
 537         cli();
 538         while ( *chainptr != NULL ) 
 539         {
 540                 struct ip_fw *ftmp;
 541                 ftmp = *chainptr;
 542                 *chainptr = ftmp->fw_next;
 543                 kfree_s(ftmp,sizeof(*ftmp));
 544         }
 545         restore_flags(flags);
 546 }
 547 
 548 /* Volatiles to keep some of the compiler versions amused */
 549 
 550 static int insert_in_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 551 {
 552         struct ip_fw *ftmp;
 553         unsigned long flags;
 554 
 555         save_flags(flags);
 556 
 557         ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC );
 558         if ( ftmp == NULL ) 
 559         {
 560 #ifdef DEBUG_CONFIG_IP_FIREWALL
 561                 printk("ip_fw_ctl:  malloc said no\n");
 562 #endif
 563                 return( ENOMEM );
 564         }
 565 
 566         memcpy(ftmp, frwl, len);
 567         /*
 568          *      Allow the more recent "minimise cost" flag to be
 569          *      set. [Rob van Nieuwkerk]
 570          */
 571         ftmp->fw_tosand |= 0x01;
 572         ftmp->fw_tosxor &= 0xFE;
 573         ftmp->fw_pcnt=0L;
 574         ftmp->fw_bcnt=0L;
 575 
 576         cli();
 577 
 578         if ((ftmp->fw_vianame)[0]) {
 579                 if (!(ftmp->fw_viadev = dev_get(ftmp->fw_vianame)))
 580                         ftmp->fw_viadev = (struct device *) -1;
 581         } else
 582                 ftmp->fw_viadev = NULL;
 583 
 584         ftmp->fw_next = *chainptr;
 585         *chainptr=ftmp;
 586         restore_flags(flags);
 587         return(0);
 588 }
 589 
 590 static int append_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 591 {
 592         struct ip_fw *ftmp;
 593         struct ip_fw *chtmp=NULL;
 594         struct ip_fw *volatile chtmp_prev=NULL;
 595         unsigned long flags;
 596 
 597         save_flags(flags);
 598 
 599         ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC );
 600         if ( ftmp == NULL ) 
 601         {
 602 #ifdef DEBUG_CONFIG_IP_FIREWALL
 603                 printk("ip_fw_ctl:  malloc said no\n");
 604 #endif
 605                 return( ENOMEM );
 606         }
 607 
 608         memcpy(ftmp, frwl, len);
 609         /*
 610          *      Allow the more recent "minimise cost" flag to be
 611          *      set. [Rob van Nieuwkerk]
 612          */
 613         ftmp->fw_tosand |= 0x01;
 614         ftmp->fw_tosxor &= 0xFE;
 615         ftmp->fw_pcnt=0L;
 616         ftmp->fw_bcnt=0L;
 617 
 618         ftmp->fw_next = NULL;
 619 
 620         cli();
 621 
 622         if ((ftmp->fw_vianame)[0]) {
 623                 if (!(ftmp->fw_viadev = dev_get(ftmp->fw_vianame)))
 624                         ftmp->fw_viadev = (struct device *) -1;
 625         } else
 626                 ftmp->fw_viadev = NULL;
 627 
 628         chtmp_prev=NULL;
 629         for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->fw_next) 
 630                 chtmp_prev=chtmp;
 631         
 632         if (chtmp_prev)
 633                 chtmp_prev->fw_next=ftmp;
 634         else
 635                 *chainptr=ftmp;
 636         restore_flags(flags);
 637         return(0);
 638 }
 639 
 640 static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl)
     /* [previous][next][first][last][top][bottom][index][help] */
 641 {
 642         struct ip_fw    *ftmp,*ltmp;
 643         unsigned short  tport1,tport2,tmpnum;
 644         char            matches,was_found;
 645         unsigned long   flags;
 646 
 647         save_flags(flags);
 648         cli();
 649 
 650         ftmp=*chainptr;
 651 
 652         if ( ftmp == NULL ) 
 653         {
 654 #ifdef DEBUG_CONFIG_IP_FIREWALL
 655                 printk("ip_fw_ctl:  chain is empty\n");
 656 #endif
 657                 restore_flags(flags);
 658                 return( EINVAL );
 659         }
 660 
 661         ltmp=NULL;
 662         was_found=0;
 663 
 664         while( !was_found && ftmp != NULL )
 665         {
 666                 matches=1;
 667                 if (ftmp->fw_src.s_addr!=frwl->fw_src.s_addr 
 668                      ||  ftmp->fw_dst.s_addr!=frwl->fw_dst.s_addr
 669                      ||  ftmp->fw_smsk.s_addr!=frwl->fw_smsk.s_addr
 670                      ||  ftmp->fw_dmsk.s_addr!=frwl->fw_dmsk.s_addr
 671                      ||  ftmp->fw_via.s_addr!=frwl->fw_via.s_addr
 672                      ||  ftmp->fw_flg!=frwl->fw_flg)
 673                         matches=0;
 674 
 675                 tport1=ftmp->fw_nsp+ftmp->fw_ndp;
 676                 tport2=frwl->fw_nsp+frwl->fw_ndp;
 677                 if (tport1!=tport2)
 678                         matches=0;
 679                 else if (tport1!=0)
 680                 {
 681                         for (tmpnum=0;tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS;tmpnum++)
 682                         if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum])
 683                                 matches=0;
 684                 }
 685                 if (strncmp(ftmp->fw_vianame, frwl->fw_vianame, IFNAMSIZ))
 686                         matches=0;
 687                 if(matches)
 688                 {
 689                         was_found=1;
 690                         if (ltmp)
 691                         {
 692                                 ltmp->fw_next=ftmp->fw_next;
 693                                 kfree_s(ftmp,sizeof(*ftmp));
 694                                 ftmp=ltmp->fw_next;
 695                         }
 696                         else
 697                         {
 698                                 *chainptr=ftmp->fw_next; 
 699                                 kfree_s(ftmp,sizeof(*ftmp));
 700                                 ftmp=*chainptr;
 701                         }       
 702                 }
 703                 else
 704                 {
 705                         ltmp = ftmp;
 706                         ftmp = ftmp->fw_next;
 707                  }
 708         }
 709         restore_flags(flags);
 710         if (was_found)
 711                 return 0;
 712         else
 713                 return(EINVAL);
 714 }
 715 
 716 #endif  /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
 717 
 718 struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 719 {
 720 
 721         if ( len != sizeof(struct ip_fw) )
 722         {
 723 #ifdef DEBUG_CONFIG_IP_FIREWALL
 724                 printk("ip_fw_ctl: len=%d, want %d\n",len, sizeof(struct ip_fw));
 725 #endif
 726                 return(NULL);
 727         }
 728 
 729         if ( (frwl->fw_flg & ~IP_FW_F_MASK) != 0 )
 730         {
 731 #ifdef DEBUG_CONFIG_IP_FIREWALL
 732                 printk("ip_fw_ctl: undefined flag bits set (flags=%x)\n",
 733                         frwl->fw_flg);
 734 #endif
 735                 return(NULL);
 736         }
 737 
 738         if ( (frwl->fw_flg & IP_FW_F_SRNG) && frwl->fw_nsp < 2 ) 
 739         {
 740 #ifdef DEBUG_CONFIG_IP_FIREWALL
 741                 printk("ip_fw_ctl: src range set but fw_nsp=%d\n",
 742                         frwl->fw_nsp);
 743 #endif
 744                 return(NULL);
 745         }
 746 
 747         if ( (frwl->fw_flg & IP_FW_F_DRNG) && frwl->fw_ndp < 2 ) 
 748         {
 749 #ifdef DEBUG_CONFIG_IP_FIREWALL
 750                 printk("ip_fw_ctl: dst range set but fw_ndp=%d\n",
 751                         frwl->fw_ndp);
 752 #endif
 753                 return(NULL);
 754         }
 755 
 756         if ( frwl->fw_nsp + frwl->fw_ndp > IP_FW_MAX_PORTS ) 
 757         {
 758 #ifdef DEBUG_CONFIG_IP_FIREWALL
 759                 printk("ip_fw_ctl: too many ports (%d+%d)\n",
 760                         frwl->fw_nsp,frwl->fw_ndp);
 761 #endif
 762                 return(NULL);
 763         }
 764 
 765         return frwl;
 766 }
 767 
 768 
 769 
 770 
 771 #ifdef CONFIG_IP_ACCT
 772 
 773 #if 0
 774 void ip_acct_cnt(struct iphdr *iph, struct device *dev, struct ip_fw *f)
     /* [previous][next][first][last][top][bottom][index][help] */
 775 {
 776         (void) ip_fw_chk(iph, dev, f, 0, 1);
 777         return;
 778 }
 779 #endif
 780 
 781 int ip_acct_ctl(int stage, void *m, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 782 {
 783         if ( stage == IP_ACCT_FLUSH )
 784         {
 785                 free_fw_chain(&ip_acct_chain);
 786                 return(0);
 787         }  
 788         if ( stage == IP_ACCT_ZERO )
 789         {
 790                 zero_fw_chain(ip_acct_chain);
 791                 return(0);
 792         }
 793         if ( stage == IP_ACCT_INSERT || stage == IP_ACCT_APPEND ||
 794                                         stage == IP_ACCT_DELETE )
 795         {
 796                 struct ip_fw *frwl;
 797 
 798                 if (!(frwl=check_ipfw_struct(m,len)))
 799                         return (EINVAL);
 800 
 801                 switch (stage) 
 802                 {
 803                         case IP_ACCT_INSERT:
 804                                 return( insert_in_chain(&ip_acct_chain,frwl,len));
 805                         case IP_ACCT_APPEND:
 806                                 return( append_to_chain(&ip_acct_chain,frwl,len));
 807                         case IP_ACCT_DELETE:
 808                                 return( del_from_chain(&ip_acct_chain,frwl));
 809                         default:
 810                                 /*
 811                                  *      Should be panic but... (Why ??? - AC)
 812                                  */
 813 #ifdef DEBUG_CONFIG_IP_FIREWALL
 814                                 printk("ip_acct_ctl:  unknown request %d\n",stage);
 815 #endif
 816                                 return(EINVAL);
 817                 }
 818         }
 819 #ifdef DEBUG_CONFIG_IP_FIREWALL
 820         printk("ip_acct_ctl:  unknown request %d\n",stage);
 821 #endif
 822         return(EINVAL);
 823 }
 824 #endif
 825 
 826 #ifdef CONFIG_IP_FIREWALL
 827 int ip_fw_ctl(int stage, void *m, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 828 {
 829         int ret, cmd, fwtype;
 830 
 831         cmd = stage & IP_FW_COMMAND;
 832         fwtype = (stage & IP_FW_TYPE) >> IP_FW_SHIFT;
 833 
 834         if ( cmd == IP_FW_FLUSH )
 835         {
 836                 free_fw_chain(chains[fwtype]);
 837                 return(0);
 838         }  
 839 
 840         if ( cmd == IP_FW_ZERO )
 841         {
 842                 zero_fw_chain(*chains[fwtype]);
 843                 return(0);
 844         }  
 845 
 846         if ( cmd == IP_FW_POLICY )
 847         {
 848                 int *tmp_policy_ptr;
 849                 tmp_policy_ptr=(int *)m;
 850                 *policies[fwtype] = *tmp_policy_ptr;
 851                 return 0;
 852         }
 853 
 854         if ( cmd == IP_FW_CHECK )
 855         {
 856                 struct device *viadev;
 857                 struct ip_fwpkt *ipfwp;
 858                 struct iphdr *ip;
 859 
 860                 if ( len != sizeof(struct ip_fwpkt) )
 861                 {
 862 #ifdef DEBUG_CONFIG_IP_FIREWALL
 863                         printk("ip_fw_ctl: length=%d, expected %d\n",
 864                                 len, sizeof(struct ip_fwpkt));
 865 #endif
 866                         return( EINVAL );
 867                 }
 868 
 869                 ipfwp = (struct ip_fwpkt *)m;
 870                 ip = &(ipfwp->fwp_iph);
 871 
 872                 if ( !(viadev = dev_get(ipfwp->fwp_vianame)) ) {
 873 #ifdef DEBUG_CONFIG_IP_FIREWALL
 874                         printk("ip_fw_ctl: invalid device \"%s\"\n", ipfwp->fwp_vianame);
 875 #endif
 876                         return(EINVAL);
 877                 } else if ( viadev->pa_addr != ipfwp->fwp_via.s_addr ) {
 878 #ifdef DEBUG_CONFIG_IP_FIREWALL
 879                         printk("ip_fw_ctl: device \"%s\" has another IP address\n",
 880                                 ipfwp->fwp_vianame);
 881 #endif
 882                         return(EINVAL);
 883                 } else if ( ip->ihl != sizeof(struct iphdr) / sizeof(int)) {
 884 #ifdef DEBUG_CONFIG_IP_FIREWALL
 885                         printk("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl,
 886                                         sizeof(struct iphdr)/sizeof(int));
 887 #endif
 888                         return(EINVAL);
 889                 }
 890 
 891                 if ((ret = ip_fw_chk(ip, viadev, *chains[fwtype],
 892                                 *policies[fwtype], 2)) == FW_ACCEPT)
 893                         return(0);
 894                 else if (ret == FW_MASQUERADE)  
 895                         return(ECONNRESET);
 896                 else if (ret == FW_REJECT)      
 897                         return(ECONNREFUSED);
 898                 else /* ret == FW_BLOCK */
 899                         return(ETIMEDOUT);
 900         }
 901 
 902         if ( cmd == IP_FW_MASQ_TIMEOUTS )
 903         {
 904 #ifdef CONFIG_IP_MASQUERADE
 905                 struct ip_fw_masq *masq;
 906 
 907                 if ( len != sizeof(struct ip_fw_masq) )
 908                 {
 909 #ifdef DEBUG_CONFIG_IP_FIREWALL
 910                         printk("ip_fw_ctl (masq): length %d, expected %d\n",
 911                                 len, sizeof(struct ip_fw_masq));
 912 
 913 #endif
 914                         return( EINVAL );
 915                 }
 916 
 917                 masq = (struct ip_fw_masq *) m;
 918 
 919                 if (masq->tcp_timeout)
 920                 {
 921                         ip_masq_expire->tcp_timeout = masq->tcp_timeout;
 922                 }
 923 
 924                 if (masq->tcp_fin_timeout)
 925                 {
 926                         ip_masq_expire->tcp_fin_timeout = masq->tcp_fin_timeout;
 927                 }
 928 
 929                 if (masq->udp_timeout)
 930                 {
 931                         ip_masq_expire->udp_timeout = masq->udp_timeout;
 932                 }
 933 
 934                 return 0;
 935 #else
 936                 return( EINVAL );
 937 #endif
 938         }
 939 
 940 /*
 941  *      Here we really working hard-adding new elements
 942  *      to blocking/forwarding chains or deleting 'em
 943  */
 944 
 945         if ( cmd == IP_FW_INSERT || cmd == IP_FW_APPEND || cmd == IP_FW_DELETE )
 946         {
 947                 struct ip_fw *frwl;
 948                 int fwtype;
 949 
 950                 frwl=check_ipfw_struct(m,len);
 951                 if (frwl==NULL)
 952                         return (EINVAL);
 953                 fwtype = (stage & IP_FW_TYPE) >> IP_FW_SHIFT;
 954                 
 955                 switch (cmd) 
 956                 {
 957                         case IP_FW_INSERT:
 958                                 return(insert_in_chain(chains[fwtype],frwl,len));
 959                         case IP_FW_APPEND:
 960                                 return(append_to_chain(chains[fwtype],frwl,len));
 961                         case IP_FW_DELETE:
 962                                 return(del_from_chain(chains[fwtype],frwl));
 963                         default:
 964                         /*
 965                          *      Should be panic but... (Why are BSD people panic obsessed ??)
 966                          */
 967 #ifdef DEBUG_CONFIG_IP_FIREWALL
 968                                 printk("ip_fw_ctl:  unknown request %d\n",stage);
 969 #endif
 970                                 return(EINVAL);
 971                 }
 972         } 
 973 
 974 #ifdef DEBUG_CONFIG_IP_FIREWALL
 975         printk("ip_fw_ctl:  unknown request %d\n",stage);
 976 #endif
 977         return(EINVAL);
 978 }
 979 #endif /* CONFIG_IP_FIREWALL */
 980 
 981 #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
 982 
 983 static int ip_chain_procinfo(int stage, char *buffer, char **start,
     /* [previous][next][first][last][top][bottom][index][help] */
 984                              off_t offset, int length, int reset)
 985 {
 986         off_t pos=0, begin=0;
 987         struct ip_fw *i;
 988         unsigned long flags;
 989         int len, p;
 990         
 991 
 992         switch(stage)
 993         {
 994 #ifdef CONFIG_IP_FIREWALL
 995                 case IP_FW_IN:
 996                         i = ip_fw_in_chain;
 997                         len=sprintf(buffer, "IP firewall input rules, default %d\n",
 998                                 ip_fw_in_policy);
 999                         break;
1000                 case IP_FW_OUT:
1001                         i = ip_fw_out_chain;
1002                         len=sprintf(buffer, "IP firewall output rules, default %d\n",
1003                                 ip_fw_out_policy);
1004                         break;
1005                 case IP_FW_FWD:
1006                         i = ip_fw_fwd_chain;
1007                         len=sprintf(buffer, "IP firewall forward rules, default %d\n",
1008                                 ip_fw_fwd_policy);
1009                         break;
1010 #endif
1011 #ifdef CONFIG_IP_ACCT
1012                 case IP_FW_ACCT:
1013                         i = ip_acct_chain;
1014                         len=sprintf(buffer,"IP accounting rules\n");
1015                         break;
1016 #endif
1017                 default:
1018                         /* this should never be reached, but safety first... */
1019                         i = NULL;
1020                         len=0;
1021                         break;
1022         }
1023 
1024         save_flags(flags);
1025         cli();
1026         
1027         while(i!=NULL)
1028         {
1029                 len+=sprintf(buffer+len,"%08lX/%08lX->%08lX/%08lX %.16s %08lX %X ",
1030                         ntohl(i->fw_src.s_addr),ntohl(i->fw_smsk.s_addr),
1031                         ntohl(i->fw_dst.s_addr),ntohl(i->fw_dmsk.s_addr),
1032                         (i->fw_vianame)[0] ? i->fw_vianame : "-",
1033                         ntohl(i->fw_via.s_addr),i->fw_flg);
1034                 len+=sprintf(buffer+len,"%u %u %-9lu %-9lu",
1035                         i->fw_nsp,i->fw_ndp, i->fw_pcnt,i->fw_bcnt);
1036                 for (p = 0; p < IP_FW_MAX_PORTS; p++)
1037                         len+=sprintf(buffer+len, " %u", i->fw_pts[p]);
1038                 len+=sprintf(buffer+len, " A%02X X%02X", i->fw_tosand, i->fw_tosxor);
1039                 buffer[len++]='\n';
1040                 buffer[len]='\0';
1041                 pos=begin+len;
1042                 if(pos<offset)
1043                 {
1044                         len=0;
1045                         begin=pos;
1046                 }
1047                 else if(reset)
1048                 {
1049                         /* This needs to be done at this specific place! */
1050                         i->fw_pcnt=0L;
1051                         i->fw_bcnt=0L;
1052                 }
1053                 if(pos>offset+length)
1054                         break;
1055                 i=i->fw_next;
1056         }
1057         restore_flags(flags);
1058         *start=buffer+(offset-begin);
1059         len-=(offset-begin);
1060         if(len>length)
1061                 len=length;     
1062         return len;
1063 }
1064 #endif
1065 
1066 #ifdef CONFIG_IP_ACCT
1067 
1068 static int ip_acct_procinfo(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
1069                             int length, int reset)
1070 {
1071         return ip_chain_procinfo(IP_FW_ACCT, buffer,start, offset,length,
1072                                  reset);
1073 }
1074 
1075 #endif
1076 
1077 #ifdef CONFIG_IP_FIREWALL
1078 
1079 static int ip_fw_in_procinfo(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
1080                               int length, int reset)
1081 {
1082         return ip_chain_procinfo(IP_FW_IN, buffer,start,offset,length,
1083                                  reset);
1084 }
1085 
1086 static int ip_fw_out_procinfo(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
1087                               int length, int reset)
1088 {
1089         return ip_chain_procinfo(IP_FW_OUT, buffer,start,offset,length,
1090                                  reset);
1091 }
1092 
1093 static int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset,
     /* [previous][next][first][last][top][bottom][index][help] */
1094                               int length, int reset)
1095 {
1096         return ip_chain_procinfo(IP_FW_FWD, buffer,start,offset,length,
1097                                  reset);
1098 }
1099 #endif
1100 
1101 
1102 #ifdef CONFIG_IP_FIREWALL
1103 /*
1104  *      Interface to the generic firewall chains.
1105  */
1106  
1107 int ipfw_input_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr)
     /* [previous][next][first][last][top][bottom][index][help] */
1108 {
1109         return ip_fw_chk(phdr, dev, ip_fw_in_chain, ip_fw_in_policy, 0);
1110 }
1111 
1112 int ipfw_output_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr)
     /* [previous][next][first][last][top][bottom][index][help] */
1113 {
1114         return ip_fw_chk(phdr, dev, ip_fw_out_chain, ip_fw_out_policy, 0);
1115 }
1116 
1117 int ipfw_forward_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr)
     /* [previous][next][first][last][top][bottom][index][help] */
1118 {
1119         return ip_fw_chk(phdr, dev, ip_fw_fwd_chain, ip_fw_fwd_policy, 0);
1120 }
1121  
1122 struct firewall_ops ipfw_ops=
1123 {
1124         NULL,
1125         ipfw_forward_check,
1126         ipfw_input_check,
1127         ipfw_output_check,
1128         PF_INET,
1129         0       /* We don't even allow a fall through so we are last */
1130 };
1131 
1132 #endif
1133 
1134 #if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
1135 
1136 int ipfw_device_event(struct notifier_block *this, unsigned long event, void *ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1137 {
1138         struct device *dev=ptr;
1139         char *devname = dev->name;
1140         unsigned long flags;
1141         struct ip_fw *fw;
1142         int chn;
1143 
1144         save_flags(flags);
1145         cli();
1146         
1147         if (event == NETDEV_UP) {
1148                 for (chn = 0; chn < IP_FW_CHAINS; chn++)
1149                         for (fw = *chains[chn]; fw; fw = fw->fw_next)
1150                                 if ((fw->fw_vianame)[0] && !strncmp(devname,
1151                                                 fw->fw_vianame, IFNAMSIZ))
1152                                         fw->fw_viadev = dev;
1153         } else if (event == NETDEV_DOWN) {
1154                 for (chn = 0; chn < IP_FW_CHAINS; chn++)
1155                         for (fw = *chains[chn]; fw; fw = fw->fw_next)
1156                                 /* we could compare just the pointers ... */
1157                                 if ((fw->fw_vianame)[0] && !strncmp(devname,
1158                                                 fw->fw_vianame, IFNAMSIZ))
1159                                         fw->fw_viadev = (struct device *) -1;
1160         }
1161 
1162         restore_flags(flags);
1163         return NOTIFY_DONE;
1164 }
1165 
1166 static struct notifier_block ipfw_dev_notifier={
1167         ipfw_device_event,
1168         NULL,
1169         0
1170 };
1171 
1172 #endif
1173 
1174 void ip_fw_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1175 {
1176 #ifdef CONFIG_IP_ACCT
1177         proc_net_register(&(struct proc_dir_entry) {
1178                 PROC_NET_IPACCT, 7, "ip_acct",
1179                 S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
1180                 0, &proc_net_inode_operations,
1181                 ip_acct_procinfo
1182         });
1183 #endif
1184 #ifdef CONFIG_IP_FIREWALL
1185 
1186         if(register_firewall(PF_INET,&ipfw_ops)<0)
1187                 panic("Unable to register IP firewall.\n");
1188                 
1189         proc_net_register(&(struct proc_dir_entry) {
1190                 PROC_NET_IPFWIN, 8, "ip_input",
1191                 S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
1192                 0, &proc_net_inode_operations,
1193                 ip_fw_in_procinfo
1194         });
1195         proc_net_register(&(struct proc_dir_entry) {
1196                 PROC_NET_IPFWOUT, 9, "ip_output",
1197                 S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
1198                 0, &proc_net_inode_operations,
1199                 ip_fw_out_procinfo
1200         });
1201         proc_net_register(&(struct proc_dir_entry) {
1202                 PROC_NET_IPFWFWD, 10, "ip_forward",
1203                 S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
1204                 0, &proc_net_inode_operations,
1205                 ip_fw_fwd_procinfo
1206         });
1207 #endif
1208 
1209 #ifdef CONFIG_IP_MASQUERADE
1210         
1211         /*
1212          *      Initialize masquerading. 
1213          */
1214         
1215         ip_masq_init();
1216 #endif
1217         
1218 #if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
1219         /* Register for device up/down reports */
1220         register_netdevice_notifier(&ipfw_dev_notifier);
1221 #endif
1222 }

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