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

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