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

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