root/net/inet/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. add_to_chain
  6. del_from_chain
  7. check_ipfw_struct
  8. ip_acct_cnt
  9. ip_acct_ctl
  10. ip_fw_ctl
  11. ip_chain_procinfo
  12. ip_acct_procinfo
  13. ip_fw_blk_procinfo
  14. ip_fw_fwd_procinfo

   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  *
  23  *      All the real work was done by .....
  24  */
  25 
  26 /*
  27  * Copyright (c) 1993 Daniel Boulet
  28  * Copyright (c) 1994 Ugen J.S.Antsilevich
  29  *
  30  * Redistribution and use in source forms, with and without modification,
  31  * are permitted provided that this entire comment appears intact.
  32  *
  33  * Redistribution in binary form may occur without any restrictions.
  34  * Obviously, it would be nice if you gave credit where credit is due
  35  * but requiring it would be too onerous.
  36  *
  37  * This software is provided ``AS IS'' without any warranties of any kind.
  38  */
  39 
  40 #include <linux/config.h>
  41 #include <asm/segment.h>
  42 #include <asm/system.h>
  43 #include <linux/types.h>
  44 #include <linux/kernel.h>
  45 #include <linux/sched.h>
  46 #include <linux/string.h>
  47 #include <linux/errno.h>
  48 #include <linux/config.h>
  49 
  50 #include <linux/socket.h>
  51 #include <linux/sockios.h>
  52 #include <linux/in.h>
  53 #include <linux/inet.h>
  54 #include <linux/netdevice.h>
  55 #include <linux/icmp.h>
  56 #include <linux/udp.h>
  57 #include "ip.h"
  58 #include "protocol.h"
  59 #include "route.h"
  60 #include "tcp.h"
  61 #include <linux/skbuff.h>
  62 #include "sock.h"
  63 #include "icmp.h"
  64 #include <linux/ip_fw.h>
  65 
  66 /*
  67  *      Implement IP packet firewall
  68  */
  69 
  70 #ifdef CONFIG_IPFIREWALL_DEBUG 
  71 #define dprintf1(a)             printk(a)
  72 #define dprintf2(a1,a2)         printk(a1,a2)
  73 #define dprintf3(a1,a2,a3)      printk(a1,a2,a3)
  74 #define dprintf4(a1,a2,a3,a4)   printk(a1,a2,a3,a4)
  75 #else
  76 #define dprintf1(a)     
  77 #define dprintf2(a1,a2)
  78 #define dprintf3(a1,a2,a3)
  79 #define dprintf4(a1,a2,a3,a4)
  80 #endif
  81 
  82 #define print_ip(a)      printf("%d.%d.%d.%d",(ntohl(a.s_addr)>>24)&0xFF,\
  83                                               (ntohl(a.s_addr)>>16)&0xFF,\
  84                                               (ntohl(a.s_addr)>>8)&0xFF,\
  85                                               (ntohl(a.s_addr))&0xFF);
  86 
  87 #ifdef IPFIREWALL_DEBUG
  88 #define dprint_ip(a)    print_ip(a)
  89 #else
  90 #define dprint_ip(a)    
  91 #endif
  92 
  93 #ifdef CONFIG_IP_FIREWALL
  94 struct ip_fw *ip_fw_fwd_chain;
  95 struct ip_fw *ip_fw_blk_chain;
  96 int ip_fw_blk_policy=IP_FW_F_ACCEPT;
  97 int ip_fw_fwd_policy=IP_FW_F_ACCEPT;
  98 #endif
  99 #ifdef CONFIG_IP_ACCT
 100 struct ip_fw *ip_acct_chain;
 101 #endif
 102 
 103 #define IP_INFO_BLK     0
 104 #define IP_INFO_FWD     1
 105 #define IP_INFO_ACCT    2
 106 
 107 
 108 /*
 109  *      Returns 1 if the port is matched by the vector, 0 otherwise
 110  */
 111 
 112 extern inline int port_match(unsigned short *portptr,int nports,unsigned short port,int range_flag)
     /* [previous][next][first][last][top][bottom][index][help] */
 113 {
 114         if (!nports)
 115                 return 1;
 116         if ( range_flag ) 
 117         {
 118                 if ( portptr[0] <= port && port <= portptr[1] ) 
 119                 {
 120                         return( 1 );
 121                 }
 122                 nports -= 2;
 123                 portptr += 2;
 124         }
 125         while ( nports-- > 0 ) 
 126         {
 127                 if ( *portptr++ == port ) 
 128                 {
 129                         return( 1 );
 130                 }
 131         }
 132         return(0);
 133 }
 134 
 135 #if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
 136 
 137 
 138 /*
 139  *      Returns 0 if packet should be dropped, 1 if it should be accepted,
 140  *      and -1 if an ICMP host unreachable packet should be sent.
 141  *      Also does accounting so you can feed it the accounting chain.
 142  *      If opt is set to 1, it means that we do this for accounting
 143  *      purposes (searches all entries and handles fragments different).
 144  *      If opt is set to 2, it doesn't count a matching packet, which
 145  *      is used when calling this for checking purposes (IP_FW_CHK_*).
 146  */
 147 
 148 
 149 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] */
 150 {
 151         struct ip_fw *f;
 152         struct tcphdr           *tcp=(struct tcphdr *)((unsigned long *)ip+ip->ihl);
 153         struct udphdr           *udp=(struct udphdr *)((unsigned long *)ip+ip->ihl);
 154         __u32                   src, dst;
 155         __u16                   src_port=0, dst_port=0;
 156         unsigned short          f_prt=0, prt;
 157         char                    notcpsyn=1, frag1, match;
 158         unsigned short          f_flag;
 159 
 160         /*
 161          *      If the chain is empty follow policy. The BSD one
 162          *      accepts anything giving you a time window while
 163          *      flushing and rebuilding the tables.
 164          */
 165          
 166         src = ip->saddr;
 167         dst = ip->daddr;
 168 
 169         /* 
 170          *      This way we handle fragmented packets.
 171          *      we ignore all fragments but the first one
 172          *      so the whole packet can't be reassembled.
 173          *      This way we relay on the full info which
 174          *      stored only in first packet.
 175          *
 176          *      Note that this theoretically allows partial packet
 177          *      spoofing. Not very dangerous but paranoid people may
 178          *      wish to play with this. It also allows the so called
 179          *      "fragment bomb" denial of service attack on some types
 180          *      of system.
 181          */
 182 
 183         frag1 = ((ntohs(ip->frag_off) & IP_OFFSET) == 0);
 184         if (!frag1 && (opt != 1) && (ip->protocol == IPPROTO_TCP ||
 185                         ip->protocol == IPPROTO_UDP))
 186                 return(1);
 187 
 188         src = ip->saddr;
 189         dst = ip->daddr;
 190 
 191         /*
 192          *      If we got interface from which packet came
 193          *      we can use the address directly. This is unlike
 194          *      4.4BSD derived systems that have an address chain
 195          *      per device. We have a device per address with dummy
 196          *      devices instead.
 197          */
 198          
 199         dprintf1("Packet ");
 200         switch(ip->protocol) 
 201         {
 202                 case IPPROTO_TCP:
 203                         dprintf1("TCP ");
 204                         /* ports stay 0 if it is not the first fragment */
 205                         if (frag1) {
 206                                 src_port=ntohs(tcp->source);
 207                                 dst_port=ntohs(tcp->dest);
 208                                 if(tcp->syn && !tcp->ack)
 209                                         /* We *DO* have SYN, value FALSE */
 210                                         notcpsyn=0;
 211                         }
 212                         prt=IP_FW_F_TCP;
 213                         break;
 214                 case IPPROTO_UDP:
 215                         dprintf1("UDP ");
 216                         /* ports stay 0 if it is not the first fragment */
 217                         if (frag1) {
 218                                 src_port=ntohs(udp->source);
 219                                 dst_port=ntohs(udp->dest);
 220                         }
 221                         prt=IP_FW_F_UDP;
 222                         break;
 223                 case IPPROTO_ICMP:
 224                         dprintf2("ICMP:%d ",((char *)portptr)[0]&0xff);
 225                         prt=IP_FW_F_ICMP;
 226                         break;
 227                 default:
 228                         dprintf2("p=%d ",ip->protocol);
 229                         prt=IP_FW_F_ALL;
 230                         break;
 231         }
 232         dprint_ip(ip->saddr);
 233         
 234         if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
 235                 /* This will print 0 when it is not the first fragment! */
 236                 dprintf2(":%d ", src_port);
 237         dprint_ip(ip->daddr);
 238         if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
 239                 /* This will print 0 when it is not the first fragment! */
 240                 dprintf2(":%d ",dst_port);
 241         dprintf1("\n");
 242 
 243         for (f=chain;f;f=f->fw_next) 
 244         {
 245                 /*
 246                  *      This is a bit simpler as we don't have to walk
 247                  *      an interface chain as you do in BSD - same logic
 248                  *      however.
 249                  */
 250 
 251                 /*
 252                  *      Match can become 0x01 (a "normal" match was found),
 253                  *      0x02 (a reverse match was found), and 0x03 (the
 254                  *      IP addresses match in both directions).
 255                  *      Now we know in which direction(s) we should look
 256                  *      for a match for the TCP/UDP ports.  Both directions
 257                  *      might match (e.g., when both addresses are on the
 258                  *      same network for which an address/mask is given), but
 259                  *      the ports might only match in one direction.
 260                  *      This was obviously wrong in the original BSD code.
 261                  */
 262                 match = 0x00;
 263 
 264                 if ((src&f->fw_smsk.s_addr)==f->fw_src.s_addr
 265                 &&  (dst&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
 266                         /* normal direction */
 267                         match |= 0x01;
 268 
 269                 if ((f->fw_flg & IP_FW_F_BIDIR) &&
 270                     (dst&f->fw_smsk.s_addr)==f->fw_src.s_addr
 271                 &&  (src&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
 272                         /* reverse direction */
 273                         match |= 0x02;
 274 
 275                 if (match)
 276                 {
 277                         /*
 278                          *      Look for a VIA match 
 279                          */
 280                         if(f->fw_via.s_addr && rif)
 281                         {
 282                                 if(rif->pa_addr!=f->fw_via.s_addr)
 283                                         continue;       /* Mismatch */
 284                         }
 285                         /*
 286                          *      Drop through - this is a match
 287                          */
 288                 }
 289                 else
 290                         continue;
 291                 
 292                 /*
 293                  *      Ok the chain addresses match.
 294                  */
 295 
 296                 f_prt=f->fw_flg&IP_FW_F_KIND;
 297                 if (f_prt!=IP_FW_F_ALL) 
 298                 {
 299                         /*
 300                          * This is actually buggy as if you set SYN flag 
 301                          * on UDP or ICMP firewall it will never work,but 
 302                          * actually it is a concern of software which sets
 303                          * firewall entries.
 304                          */
 305                          
 306                          if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn)
 307                                 continue;
 308                         /*
 309                          *      Specific firewall - packet's protocol
 310                          *      must match firewall's.
 311                          */
 312 
 313                         if(prt!=f_prt)
 314                                 continue;
 315                                 
 316                         if(!(prt==IP_FW_F_ICMP || ((match & 0x01) &&
 317                                 port_match(&f->fw_pts[0], f->fw_nsp, src_port,
 318                                         f->fw_flg&IP_FW_F_SRNG) &&
 319                                 port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port,
 320                                         f->fw_flg&IP_FW_F_DRNG)) || ((match & 0x02) &&
 321                                 port_match(&f->fw_pts[0], f->fw_nsp, dst_port,
 322                                         f->fw_flg&IP_FW_F_SRNG) &&
 323                                 port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, src_port,
 324                                         f->fw_flg&IP_FW_F_DRNG))))
 325                         {
 326                                 continue;
 327                         }
 328                 }
 329 #ifdef CONFIG_IP_FIREWALL_VERBOSE
 330                 /*
 331                  * VERY ugly piece of code which actually
 332                  * makes kernel printf for denied packets...
 333                  */
 334 
 335                 if (f->fw_flg & IP_FW_F_PRN)
 336                 {
 337                         if(opt != 1) {
 338                                 if(f->fw_flg&IP_FW_F_ACCEPT)
 339                                         printk("Accept ");
 340                                 else if(f->fw_flg&IP_FW_F_ICMPRPL)
 341                                         printk("Reject ");
 342                                 else
 343                                         printk("Deny ");
 344                         }
 345                         switch(ip->protocol)
 346                         {
 347                                 case IPPROTO_TCP:
 348                                         printk("TCP ");
 349                                         break;
 350                                 case IPPROTO_UDP:
 351                                         printk("UDP ");
 352                                 case IPPROTO_ICMP:
 353                                         printk("ICMP ");
 354                                         break;
 355                                 default:
 356                                         printk("p=%d ",ip->protocol);
 357                                         break;
 358                         }
 359                         print_ip(ip->saddr);
 360                         if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
 361                                 printk(":%d", src_port);
 362                         printk(" ");
 363                         print_ip(ip->daddr);
 364                         if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
 365                                 printk(":%d",dst_port);
 366                         printk("\n");
 367                 }
 368 #endif          
 369                 if (opt != 2) {
 370                         f->fw_bcnt+=ntohs(ip->tot_len);
 371                         f->fw_pcnt++;
 372                 }
 373                 if (opt != 1)
 374                         break;
 375         } /* Loop */
 376         
 377         if(opt == 1)
 378                 return 0;
 379 
 380         /*
 381          * We rely on policy defined in the rejecting entry or, if no match
 382          * was found, we rely on the general policy variable for this type
 383          * of firewall.
 384          */
 385 
 386         if(f!=NULL)     /* A match was found */
 387                 f_flag=f->fw_flg;
 388         else
 389                 f_flag=policy;
 390         if(f_flag&IP_FW_F_ACCEPT)
 391                 return 1;
 392         if(f_flag&IP_FW_F_ICMPRPL)
 393                 return -1;
 394         return 0;
 395 }
 396 
 397 
 398 static void zero_fw_chain(struct ip_fw *chainptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 399 {
 400         struct ip_fw *ctmp=chainptr;
 401         while(ctmp) 
 402         {
 403                 ctmp->fw_pcnt=0L;
 404                 ctmp->fw_bcnt=0L;
 405                 ctmp=ctmp->fw_next;
 406         }
 407 }
 408 
 409 static void free_fw_chain(struct ip_fw *volatile* chainptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 410 {
 411         unsigned long flags;
 412         save_flags(flags);
 413         cli();
 414         while ( *chainptr != NULL ) 
 415         {
 416                 struct ip_fw *ftmp;
 417                 ftmp = *chainptr;
 418                 *chainptr = ftmp->fw_next;
 419                 kfree_s(ftmp,sizeof(*ftmp));
 420         }
 421         restore_flags(flags);
 422 }
 423 
 424 /* Volatiles to keep some of the compiler versions amused */
 425 
 426 static int add_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl)
     /* [previous][next][first][last][top][bottom][index][help] */
 427 {
 428         struct ip_fw *ftmp;
 429         struct ip_fw *chtmp=NULL;
 430         struct ip_fw *volatile chtmp_prev=NULL;
 431         unsigned long flags;
 432         unsigned long m_src_mask,m_dst_mask;
 433         unsigned long n_sa,n_da,o_sa,o_da,o_sm,o_dm,n_sm,n_dm;
 434         unsigned short n_sr,n_dr,o_sr,o_dr; 
 435         unsigned short oldkind,newkind;
 436         int addb4=0;
 437         int n_o,n_n;
 438         
 439         save_flags(flags);
 440         
 441         ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC );
 442         if ( ftmp == NULL ) 
 443         {
 444 #ifdef DEBUG_CONFIG_IP_FIREWALL
 445                 printf("ip_fw_ctl:  malloc said no\n");
 446 #endif
 447                 return( ENOMEM );
 448         }
 449 
 450         memcpy(ftmp, frwl, sizeof( struct ip_fw ) );
 451         
 452         ftmp->fw_pcnt=0L;
 453         ftmp->fw_bcnt=0L;
 454 
 455         ftmp->fw_next = NULL;
 456 
 457         cli();
 458         
 459         if (*chainptr==NULL)
 460         {
 461                 *chainptr=ftmp;
 462         }
 463         else
 464         {
 465                 chtmp_prev=NULL;
 466                 for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->fw_next) 
 467                 {
 468                         addb4=0;
 469                         newkind=ftmp->fw_flg & IP_FW_F_KIND;
 470                         oldkind=chtmp->fw_flg & IP_FW_F_KIND;
 471         
 472                         if (newkind!=IP_FW_F_ALL 
 473                                 &&  oldkind!=IP_FW_F_ALL
 474                                 &&  oldkind!=newkind) 
 475                         {
 476                                 chtmp_prev=chtmp;
 477                                 continue;
 478                         }
 479 
 480                         /*
 481                          *      Very very *UGLY* code...
 482                          *      Sorry,but i had to do this....
 483                          */
 484 
 485                         n_sa=ntohl(ftmp->fw_src.s_addr);
 486                         n_da=ntohl(ftmp->fw_dst.s_addr);
 487                         n_sm=ntohl(ftmp->fw_smsk.s_addr);
 488                         n_dm=ntohl(ftmp->fw_dmsk.s_addr);
 489 
 490                         o_sa=ntohl(chtmp->fw_src.s_addr);
 491                         o_da=ntohl(chtmp->fw_dst.s_addr);
 492                         o_sm=ntohl(chtmp->fw_smsk.s_addr);
 493                         o_dm=ntohl(chtmp->fw_dmsk.s_addr);
 494 
 495                         m_src_mask = o_sm & n_sm;
 496                         m_dst_mask = o_dm & n_dm;
 497 
 498                         if ((o_sa & m_src_mask) == (n_sa & m_src_mask)) 
 499                         {
 500                                 if (n_sm > o_sm) 
 501                                         addb4++;
 502                                 if (n_sm < o_sm) 
 503                                         addb4--;
 504                         }
 505                 
 506                         if ((o_da & m_dst_mask) == (n_da & m_dst_mask)) 
 507                         {
 508                                 if (n_dm > o_dm)
 509                                         addb4++;
 510                                 if (n_dm < o_dm)
 511                                         addb4--;
 512                         }
 513 
 514                         if (((o_da & o_dm) == (n_da & n_dm))
 515                                 &&((o_sa & o_sm) == (n_sa & n_sm)))
 516                         {
 517                                 if (newkind!=IP_FW_F_ALL &&
 518                                         oldkind==IP_FW_F_ALL)
 519                                         addb4++;
 520                                 if (newkind==oldkind && (oldkind==IP_FW_F_TCP
 521                                         ||  oldkind==IP_FW_F_UDP)) 
 522                                 {
 523         
 524                                         /*
 525                                          *      Here the main idea is to check the size
 526                                          *      of port range which the frwl covers
 527                                          *      We actually don't check their values but
 528                                          *      just the wideness of range they have
 529                                          *      so that less wide ranges or single ports
 530                                          *      go first and wide ranges go later. No ports
 531                                          *      at all treated as a range of maximum number
 532                                          *      of ports.
 533                                          */
 534 
 535                                         if (ftmp->fw_flg & IP_FW_F_SRNG) 
 536                                                 n_sr=ftmp->fw_pts[1]-ftmp->fw_pts[0];
 537                                         else 
 538                                                 n_sr=(ftmp->fw_nsp)?
 539                                                         ftmp->fw_nsp : 0xFFFF;
 540                                                 
 541                                         if (chtmp->fw_flg & IP_FW_F_SRNG) 
 542                                                 o_sr=chtmp->fw_pts[1]-chtmp->fw_pts[0];
 543                                         else 
 544                                                 o_sr=(chtmp->fw_nsp)?chtmp->fw_nsp : 0xFFFF;
 545 
 546                                         if (n_sr<o_sr)
 547                                                 addb4++;
 548                                         if (n_sr>o_sr)
 549                                                 addb4--;
 550                                         
 551                                         n_n=ftmp->fw_nsp;
 552                                         n_o=chtmp->fw_nsp;
 553         
 554                                         /*
 555                                          * Actually this cannot happen as the frwl control
 556                                          * procedure checks for number of ports in source and
 557                                          * destination range but we will try to be more safe.
 558                                          */
 559                                          
 560                                         if ((n_n>(IP_FW_MAX_PORTS-2)) ||
 561                                                 (n_o>(IP_FW_MAX_PORTS-2)))
 562                                                 goto skip_check;
 563 
 564                                         if (ftmp->fw_flg & IP_FW_F_DRNG) 
 565                                                n_dr=ftmp->fw_pts[n_n+1]-ftmp->fw_pts[n_n];
 566                                         else 
 567                                                n_dr=(ftmp->fw_ndp)? ftmp->fw_ndp : 0xFFFF;
 568 
 569                                         if (chtmp->fw_flg & IP_FW_F_DRNG) 
 570                                                 o_dr=chtmp->fw_pts[n_o+1]-chtmp->fw_pts[n_o];
 571                                         else 
 572                                                 o_dr=(chtmp->fw_ndp)? chtmp->fw_ndp : 0xFFFF;
 573                                         if (n_dr<o_dr)
 574                                                 addb4++;
 575                                         if (n_dr>o_dr)
 576                                                 addb4--;
 577 skip_check:
 578                                 }
 579                                 /* finally look at the interface address */
 580                                 if ((addb4 == 0) && ftmp->fw_via.s_addr &&
 581                                                 !(chtmp->fw_via.s_addr))
 582                                         addb4++;
 583                         }
 584                         if (addb4>0) 
 585                         {
 586                                 if (chtmp_prev) 
 587                                 {
 588                                         chtmp_prev->fw_next=ftmp; 
 589                                         ftmp->fw_next=chtmp;
 590                                 } 
 591                                 else 
 592                                 {
 593                                         *chainptr=ftmp;
 594                                         ftmp->fw_next=chtmp;
 595                                 }
 596                                 restore_flags(flags);
 597                                 return 0;
 598                         }
 599                         chtmp_prev=chtmp;
 600                 }
 601         }
 602         
 603         if (chtmp_prev)
 604                 chtmp_prev->fw_next=ftmp;
 605         else
 606                 *chainptr=ftmp;
 607         restore_flags(flags);
 608         return(0);
 609 }
 610 
 611 static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl)
     /* [previous][next][first][last][top][bottom][index][help] */
 612 {
 613         struct ip_fw    *ftmp,*ltmp;
 614         unsigned short  tport1,tport2,tmpnum;
 615         char            matches,was_found;
 616         unsigned long   flags;
 617 
 618         save_flags(flags);
 619         cli();
 620         
 621         ftmp=*chainptr;
 622 
 623         if ( ftmp == NULL ) 
 624         {
 625 #ifdef DEBUG_CONFIG_IP_FIREWALL
 626                 printk("ip_fw_ctl:  chain is empty\n");
 627 #endif
 628                 restore_flags(flags);
 629                 return( EINVAL );
 630         }
 631 
 632         ltmp=NULL;
 633         was_found=0;
 634 
 635         while( ftmp != NULL )
 636         {
 637                 matches=1;
 638              if (ftmp->fw_src.s_addr!=frwl->fw_src.s_addr 
 639                      ||  ftmp->fw_dst.s_addr!=frwl->fw_dst.s_addr
 640                      ||  ftmp->fw_smsk.s_addr!=frwl->fw_smsk.s_addr
 641                      ||  ftmp->fw_dmsk.s_addr!=frwl->fw_dmsk.s_addr
 642                      ||  ftmp->fw_via.s_addr!=frwl->fw_via.s_addr
 643                      ||  ftmp->fw_flg!=frwl->fw_flg)
 644                         matches=0;
 645 
 646                 tport1=ftmp->fw_nsp+ftmp->fw_ndp;
 647                 tport2=frwl->fw_nsp+frwl->fw_ndp;
 648                 if (tport1!=tport2)
 649                         matches=0;
 650                 else if (tport1!=0)
 651                 {
 652                         for (tmpnum=0;tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS;tmpnum++)
 653                         if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum])
 654                                 matches=0;
 655                 }
 656                 if(matches)
 657                 {
 658                         was_found=1;
 659                         if (ltmp)
 660                         {
 661                                 ltmp->fw_next=ftmp->fw_next;
 662                                 kfree_s(ftmp,sizeof(*ftmp));
 663                                 ftmp=ltmp->fw_next;
 664                         }
 665                         else
 666                         {
 667                                 *chainptr=ftmp->fw_next; 
 668                                 kfree_s(ftmp,sizeof(*ftmp));
 669                                 ftmp=*chainptr;
 670                         }       
 671                 }
 672                 else
 673                 {
 674                         ltmp = ftmp;
 675                         ftmp = ftmp->fw_next;
 676                  }
 677         }
 678         restore_flags(flags);
 679         if (was_found)
 680                 return 0;
 681         else
 682                 return(EINVAL);
 683 }
 684 
 685 #endif  /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
 686 
 687 struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 688 {
 689 
 690         if ( len != sizeof(struct ip_fw) )
 691         {
 692 #ifdef DEBUG_CONFIG_IP_FIREWALL
 693                 printk("ip_fw_ctl: len=%d, want %d\n",m->m_len,
 694                                         sizeof(struct ip_fw));
 695 #endif
 696                 return(NULL);
 697         }
 698 
 699         if ( (frwl->fw_flg & ~IP_FW_F_MASK) != 0 )
 700         {
 701 #ifdef DEBUG_CONFIG_IP_FIREWALL
 702                 printk("ip_fw_ctl: undefined flag bits set (flags=%x)\n",
 703                         frwl->fw_flg);
 704 #endif
 705                 return(NULL);
 706         }
 707 
 708         if ( (frwl->fw_flg & IP_FW_F_SRNG) && frwl->fw_nsp < 2 ) 
 709         {
 710 #ifdef DEBUG_CONFIG_IP_FIREWALL
 711                 printk("ip_fw_ctl: src range set but n_src_p=%d\n",
 712                         frwl->fw_nsp);
 713 #endif
 714                 return(NULL);
 715         }
 716 
 717         if ( (frwl->fw_flg & IP_FW_F_DRNG) && frwl->fw_ndp < 2 ) 
 718         {
 719 #ifdef DEBUG_CONFIG_IP_FIREWALL
 720                 printk("ip_fw_ctl: dst range set but n_dst_p=%d\n",
 721                         frwl->fw_ndp);
 722 #endif
 723                 return(NULL);
 724         }
 725 
 726         if ( frwl->fw_nsp + frwl->fw_ndp > IP_FW_MAX_PORTS ) 
 727         {
 728 #ifdef DEBUG_CONFIG_IP_FIREWALL
 729                 printk("ip_fw_ctl: too many ports (%d+%d)\n",
 730                         frwl->fw_nsp,frwl->fw_ndp);
 731 #endif
 732                 return(NULL);
 733         }
 734 
 735         return frwl;
 736 }
 737 
 738 
 739 
 740 
 741 #ifdef CONFIG_IP_ACCT
 742 
 743 void ip_acct_cnt(struct iphdr *iph, struct device *dev, struct ip_fw *f)
     /* [previous][next][first][last][top][bottom][index][help] */
 744 {
 745         (void) ip_fw_chk(iph, dev, f, 0, 1);
 746         return;
 747 }
 748 
 749 int ip_acct_ctl(int stage, void *m, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 750 {
 751         if ( stage == IP_ACCT_FLUSH )
 752         {
 753                 free_fw_chain(&ip_acct_chain);
 754                 return(0);
 755         }  
 756         if ( stage == IP_ACCT_ZERO )
 757         {
 758                 zero_fw_chain(ip_acct_chain);
 759                 return(0);
 760         }
 761         if ( stage == IP_ACCT_ADD
 762           || stage == IP_ACCT_DEL
 763            )
 764         {
 765                 struct ip_fw *frwl;
 766 
 767                 if (!(frwl=check_ipfw_struct(m,len)))
 768                         return (EINVAL);
 769 
 770                 switch (stage) 
 771                 {
 772                         case IP_ACCT_ADD:
 773                                 return( add_to_chain(&ip_acct_chain,frwl));
 774                         case IP_ACCT_DEL:
 775                                 return( del_from_chain(&ip_acct_chain,frwl));
 776                         default:
 777                                 /*
 778                                  *      Should be panic but... (Why ??? - AC)
 779                                  */
 780 #ifdef DEBUG_CONFIG_IP_FIREWALL
 781                                 printf("ip_acct_ctl:  unknown request %d\n",stage);
 782 #endif
 783                                 return(EINVAL);
 784                 }
 785         }
 786 #ifdef DEBUG_CONFIG_IP_FIREWALL
 787         printf("ip_acct_ctl:  unknown request %d\n",stage);
 788 #endif
 789         return(EINVAL);
 790 }
 791 #endif
 792 
 793 #ifdef CONFIG_IP_FIREWALL
 794 int ip_fw_ctl(int stage, void *m, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 795 {
 796         int ret;
 797 
 798         if ( stage == IP_FW_FLUSH_BLK )
 799         {
 800                 free_fw_chain(&ip_fw_blk_chain);
 801                 return(0);
 802         }  
 803 
 804         if ( stage == IP_FW_FLUSH_FWD )
 805         {
 806                 free_fw_chain(&ip_fw_fwd_chain);
 807                 return(0);
 808         }  
 809 
 810         if ( stage == IP_FW_ZERO_BLK )
 811         {
 812                 zero_fw_chain(ip_fw_blk_chain);
 813                 return(0);
 814         }  
 815 
 816         if ( stage == IP_FW_ZERO_FWD )
 817         {
 818                 zero_fw_chain(ip_fw_fwd_chain);
 819                 return(0);
 820         }  
 821 
 822         if ( stage == IP_FW_POLICY_BLK || stage == IP_FW_POLICY_FWD )
 823         {
 824                 int *tmp_policy_ptr;
 825                 tmp_policy_ptr=(int *)m;
 826                 if ( stage == IP_FW_POLICY_BLK )
 827                         ip_fw_blk_policy=*tmp_policy_ptr;
 828                 else
 829                         ip_fw_fwd_policy=*tmp_policy_ptr;
 830                 return 0;
 831         }
 832 
 833         if ( stage == IP_FW_CHK_BLK || stage == IP_FW_CHK_FWD )
 834         {
 835                 struct device viadev;
 836                 struct ip_fwpkt *ipfwp;
 837                 struct iphdr *ip;
 838 
 839                 if ( len < sizeof(struct ip_fwpkt) )
 840                 {
 841 #ifdef DEBUG_CONFIG_IP_FIREWALL
 842                         printf("ip_fw_ctl: length=%d, expected %d\n",
 843                                 len, sizeof(struct ip_fwpkt));
 844 #endif
 845                         return( EINVAL );
 846                 }
 847 
 848                 ipfwp = (struct ip_fwpkt *)m;
 849                 ip = &(ipfwp->fwp_iph);
 850 
 851                 if ( ip->ihl != sizeof(struct iphdr) / sizeof(int))
 852                 {
 853 #ifdef DEBUG_CONFIG_IP_FIREWALL
 854                         printf("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl,
 855                                         sizeof(struct ip)/sizeof(int));
 856 #endif
 857                         return(EINVAL);
 858                 }
 859 
 860                 viadev.pa_addr = ipfwp->fwp_via.s_addr;
 861 
 862                 if ((ret = ip_fw_chk(ip, &viadev,
 863                         stage == IP_FW_CHK_BLK ?
 864                         ip_fw_blk_chain : ip_fw_fwd_chain,
 865                         stage == IP_FW_CHK_BLK ?
 866                         ip_fw_blk_policy : ip_fw_fwd_policy, 2 )) > 0
 867                    )
 868                         return(0);
 869                 else if (ret == -1)     
 870                         return(ECONNREFUSED);
 871                 else
 872                         return(ETIMEDOUT);
 873         }
 874 
 875 /*
 876  *      Here we really working hard-adding new elements
 877  *      to blocking/forwarding chains or deleting 'em
 878  */
 879 
 880         if ( stage == IP_FW_ADD_BLK || stage == IP_FW_ADD_FWD
 881                 || stage == IP_FW_DEL_BLK || stage == IP_FW_DEL_FWD
 882                 )
 883         {
 884                 struct ip_fw *frwl;
 885                 frwl=check_ipfw_struct(m,len);
 886                 if (frwl==NULL)
 887                         return (EINVAL);
 888                 
 889                 switch (stage) 
 890                 {
 891                         case IP_FW_ADD_BLK:
 892                                 return(add_to_chain(&ip_fw_blk_chain,frwl));
 893                         case IP_FW_ADD_FWD:
 894                                 return(add_to_chain(&ip_fw_fwd_chain,frwl));
 895                         case IP_FW_DEL_BLK:
 896                                 return(del_from_chain(&ip_fw_blk_chain,frwl));
 897                         case IP_FW_DEL_FWD: 
 898                                 return(del_from_chain(&ip_fw_fwd_chain,frwl));
 899                         default:
 900                         /*
 901                          *      Should be panic but... (Why are BSD people panic obsessed ??)
 902                          */
 903 #ifdef DEBUG_CONFIG_IP_FIREWALL
 904                                 printk("ip_fw_ctl:  unknown request %d\n",stage);
 905 #endif
 906                                 return(EINVAL);
 907                 }
 908         } 
 909 
 910 #ifdef DEBUG_CONFIG_IP_FIREWALL
 911         printf("ip_fw_ctl:  unknown request %d\n",stage);
 912 #endif
 913         return(EINVAL);
 914 }
 915 #endif /* CONFIG_IP_FIREWALL */
 916 
 917 #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
 918 
 919 static int ip_chain_procinfo(int stage, char *buffer, char **start,
     /* [previous][next][first][last][top][bottom][index][help] */
 920                 off_t offset, int length, int reset)
 921 {
 922         off_t pos=0, begin=0;
 923         struct ip_fw *i;
 924         unsigned long flags;
 925         int len, p;
 926         
 927 
 928         switch(stage)
 929         {
 930 #ifdef CONFIG_IP_FIREWALL
 931                 case IP_INFO_BLK:
 932                         i = ip_fw_blk_chain;
 933                         len=sprintf(buffer, "IP firewall block rules, default %d\n",
 934                                 ip_fw_blk_policy);
 935                         break;
 936                 case IP_INFO_FWD:
 937                         i = ip_fw_fwd_chain;
 938                         len=sprintf(buffer, "IP firewall forward rules, default %d\n",
 939                                 ip_fw_fwd_policy);
 940                         break;
 941 #endif
 942 #ifdef CONFIG_IP_ACCT
 943                 case IP_INFO_ACCT:
 944                         i = ip_acct_chain;
 945                         len=sprintf(buffer,"IP accounting rules\n");
 946                         break;
 947 #endif
 948                 default:
 949                         /* this should never be reached, but safety first... */
 950                         i = NULL;
 951                         len=0;
 952                         break;
 953         }
 954 
 955         save_flags(flags);
 956         cli();
 957         
 958         while(i!=NULL)
 959         {
 960                 len+=sprintf(buffer+len,"%08lX/%08lX->%08lX/%08lX %08lX %X ",
 961                         ntohl(i->fw_src.s_addr),ntohl(i->fw_smsk.s_addr),
 962                         ntohl(i->fw_dst.s_addr),ntohl(i->fw_dmsk.s_addr),
 963                         ntohl(i->fw_via.s_addr),i->fw_flg);
 964                 len+=sprintf(buffer+len,"%u %u %10lu %10lu",
 965                         i->fw_nsp,i->fw_ndp, i->fw_pcnt,i->fw_bcnt);
 966                 for (p = 0; p < IP_FW_MAX_PORTS; p++)
 967                         len+=sprintf(buffer+len, " %u", i->fw_pts[p]);
 968                 buffer[len++]='\n';
 969                 buffer[len]='\0';
 970                 pos=begin+len;
 971                 if(pos<offset)
 972                 {
 973                         len=0;
 974                         begin=pos;
 975                 }
 976                 else if(reset)
 977                 {
 978                         /* This needs to be done at this specific place! */
 979                         i->fw_pcnt=0L;
 980                         i->fw_bcnt=0L;
 981                 }
 982                 if(pos>offset+length)
 983                         break;
 984                 i=i->fw_next;
 985         }
 986         restore_flags(flags);
 987         *start=buffer+(offset-begin);
 988         len-=(offset-begin);
 989         if(len>length)
 990                 len=length;     
 991         return len;
 992 }
 993 #endif
 994 
 995 #ifdef CONFIG_IP_ACCT
 996 
 997 int ip_acct_procinfo(char *buffer, char **start, off_t offset, int length, int reset)
     /* [previous][next][first][last][top][bottom][index][help] */
 998 {
 999         return ip_chain_procinfo(IP_INFO_ACCT, buffer,start,offset,length,reset);
1000 }
1001 
1002 #endif
1003 
1004 #ifdef CONFIG_IP_FIREWALL
1005 
1006 int ip_fw_blk_procinfo(char *buffer, char **start, off_t offset, int length, int reset)
     /* [previous][next][first][last][top][bottom][index][help] */
1007 {
1008         return ip_chain_procinfo(IP_INFO_BLK, buffer,start,offset,length,reset);
1009 }
1010 
1011 int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset, int length, int reset)
     /* [previous][next][first][last][top][bottom][index][help] */
1012 {
1013         return ip_chain_procinfo(IP_INFO_FWD, buffer,start,offset,length,reset);
1014 }
1015 
1016 #endif

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