The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/ip_state.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (C) 1995-1997 by Darren Reed.
    3  *
    4  * Redistribution and use in source and binary forms are permitted
    5  * provided that this notice is preserved and due credit is given
    6  * to the original author and the contributors.
    7  */
    8 #if !defined(lint)
    9 static const char sccsid[] = "@(#)ip_state.c    1.8 6/5/96 (C) 1993-1995 Darren Reed";
   10 static const char rcsid[] = "@(#)$FreeBSD$";
   11 #endif
   12 
   13 #include "opt_ipfilter.h"
   14 #if defined(KERNEL) && !defined(_KERNEL)
   15 #define _KERNEL
   16 #endif
   17 #define __FreeBSD_version 300000        /* it's a hack, but close enough */
   18 
   19 #if !defined(_KERNEL) && !defined(KERNEL) && !defined(__KERNEL__)
   20 # include <stdlib.h>
   21 # include <string.h>
   22 #else
   23 # ifdef linux
   24 #  include <linux/kernel.h>
   25 #  include <linux/module.h>
   26 # endif
   27 #endif
   28 #include <sys/errno.h>
   29 #include <sys/types.h>
   30 #include <sys/param.h>
   31 #include <sys/file.h>
   32 #if defined(KERNEL) && (__FreeBSD_version >= 220000)
   33 # include <sys/filio.h>
   34 # include <sys/fcntl.h>
   35 # include <sys/malloc.h>
   36 #else
   37 # include <sys/ioctl.h>
   38 #endif
   39 #include <sys/time.h>
   40 #include <sys/uio.h>
   41 #ifndef linux
   42 #include <sys/protosw.h>
   43 #endif
   44 #include <sys/socket.h>
   45 #if defined(_KERNEL) && !defined(linux)
   46 # include <sys/systm.h>
   47 #endif
   48 #if !defined(__SVR4) && !defined(__svr4__)
   49 # ifndef linux
   50 #  include <sys/mbuf.h>
   51 # endif
   52 #else
   53 # include <sys/filio.h>
   54 # include <sys/byteorder.h>
   55 # include <sys/dditypes.h>
   56 # include <sys/stream.h>
   57 # include <sys/kmem.h>
   58 #endif
   59 
   60 #include <net/if.h>
   61 #ifdef sun
   62 #include <net/af.h>
   63 #endif
   64 #include <net/route.h>
   65 #include <netinet/in.h>
   66 #include <netinet/in_systm.h>
   67 #include <netinet/ip.h>
   68 #include <netinet/tcp.h>
   69 #ifndef linux
   70 # include <netinet/ip_var.h>
   71 # include <netinet/tcp_fsm.h>
   72 #endif
   73 #include <netinet/udp.h>
   74 #include <netinet/ip_icmp.h>
   75 #include "netinet/ip_compat.h"
   76 #include <netinet/tcpip.h>
   77 #include "netinet/ip_fil.h"
   78 #include "netinet/ip_nat.h"
   79 #include "netinet/ip_frag.h"
   80 #include "netinet/ip_proxy.h"
   81 #include "netinet/ip_state.h"
   82 #ifndef MIN
   83 #define MIN(a,b)        (((a)<(b))?(a):(b))
   84 #endif
   85 
   86 #define TCP_CLOSE       (TH_FIN|TH_RST)
   87 
   88 static ipstate_t *ips_table[IPSTATE_SIZE];
   89 static int      ips_num = 0;
   90 static ips_stat_t ips_stats;
   91 #if     (SOLARIS || defined(__sgi)) && defined(_KERNEL)
   92 extern  kmutex_t        ipf_state;
   93 #endif
   94 
   95 static int fr_matchsrcdst __P((ipstate_t *, struct in_addr, struct in_addr,
   96                                fr_info_t *, void *, u_short, u_short));
   97 static int fr_state_flush __P((int));
   98 static ips_stat_t *fr_statetstats __P((void));
   99 
  100 
  101 #define FIVE_DAYS       (2 * 5 * 86400) /* 5 days: half closed session */
  102 
  103 u_long  fr_tcpidletimeout = FIVE_DAYS,
  104         fr_tcpclosewait = 60,
  105         fr_tcplastack = 20,
  106         fr_tcptimeout = 120,
  107         fr_tcpclosed = 1,
  108         fr_udptimeout = 120,
  109         fr_icmptimeout = 120;
  110 
  111 
  112 static ips_stat_t *fr_statetstats()
  113 {
  114         ips_stats.iss_active = ips_num;
  115         ips_stats.iss_table = ips_table;
  116         return &ips_stats;
  117 }
  118 
  119 
  120 /*
  121  * flush state tables.  two actions currently defined:
  122  * which == 0 : flush all state table entries
  123  * which == 1 : flush TCP connections which have started to close but are
  124  *              stuck for some reason.
  125  */
  126 static int fr_state_flush(which)
  127 int which;
  128 {
  129         register int i;
  130         register ipstate_t *is, **isp;
  131 #if defined(_KERNEL) && !SOLARIS
  132         int s;
  133 #endif
  134         int delete, removed = 0;
  135 
  136         SPL_NET(s);
  137         MUTEX_ENTER(&ipf_state);
  138         for (i = 0; i < IPSTATE_SIZE; i++)
  139                 for (isp = &ips_table[i]; (is = *isp); ) {
  140                         delete = 0;
  141 
  142                         switch (which)
  143                         {
  144                         case 0 :
  145                                 delete = 1;
  146                                 break;
  147                         case 1 :
  148                                 if ((is->is_p == IPPROTO_TCP) &&
  149                                     (((is->is_state[0] <= TCPS_ESTABLISHED) &&
  150                                       (is->is_state[1] > TCPS_ESTABLISHED)) ||
  151                                      ((is->is_state[1] <= TCPS_ESTABLISHED) &&
  152                                       (is->is_state[0] > TCPS_ESTABLISHED))))
  153                                         delete = 1;
  154                                 break;
  155                         }
  156 
  157                         if (delete) {
  158                                 *isp = is->is_next;
  159                                 if (is->is_p == IPPROTO_TCP)
  160                                         ips_stats.iss_fin++;
  161                                 else
  162                                         ips_stats.iss_expire++;
  163 #ifdef  IPFILTER_LOG
  164                                 ipstate_log(is, ISL_FLUSH);
  165 #endif
  166                                 KFREE(is);
  167                                 ips_num--;
  168                                 removed++;
  169                         } else
  170                                 isp = &is->is_next;
  171                 }
  172         MUTEX_EXIT(&ipf_state);
  173         SPL_X(s);
  174         return removed;
  175 }
  176 
  177 
  178 int fr_state_ioctl(data, cmd, mode)
  179 caddr_t data;
  180 #if defined(__NetBSD__) || defined(__OpenBSD__)
  181 u_long cmd;
  182 #else
  183 int cmd;
  184 #endif
  185 int mode;
  186 {
  187         int     arg, ret, error = 0;
  188 
  189         switch (cmd)
  190         {
  191         case SIOCIPFFL :
  192                 IRCOPY(data, (caddr_t)&arg, sizeof(arg));
  193                 if (arg == 0 || arg == 1) {
  194                         ret = fr_state_flush(arg);
  195                         IWCOPY((caddr_t)&ret, data, sizeof(ret));
  196                 } else
  197                         error = EINVAL;
  198                 break;
  199         case SIOCGIPST :
  200                 IWCOPY((caddr_t)fr_statetstats(), data, sizeof(ips_stat_t));
  201                 break;
  202         case FIONREAD :
  203 #ifdef  IPFILTER_LOG
  204                 IWCOPY((caddr_t)&iplused[IPL_LOGSTATE], (caddr_t)data,
  205                        sizeof(iplused[IPL_LOGSTATE]));
  206 #endif
  207                 break;
  208         default :
  209                 return EINVAL;
  210         }
  211         return error;
  212 }
  213 
  214 
  215 /*
  216  * Create a new ipstate structure and hang it off the hash table.
  217  */
  218 int fr_addstate(ip, fin, pass)
  219 ip_t *ip;
  220 fr_info_t *fin;
  221 u_int pass;
  222 {
  223         ipstate_t ips;
  224         register ipstate_t *is = &ips;
  225         register u_int hv;
  226 
  227         if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT))
  228                 return -1;
  229         if (ips_num == IPSTATE_MAX) {
  230                 ips_stats.iss_max++;
  231                 return -1;
  232         }
  233         ips.is_age = 1;
  234         ips.is_state[0] = 0;
  235         ips.is_state[1] = 0;
  236         /*
  237          * Copy and calculate...
  238          */
  239         hv = (is->is_p = ip->ip_p);
  240         hv += (is->is_src.s_addr = ip->ip_src.s_addr);
  241         hv += (is->is_dst.s_addr = ip->ip_dst.s_addr);
  242 
  243         switch (ip->ip_p)
  244         {
  245         case IPPROTO_ICMP :
  246             {
  247                 struct icmp *ic = (struct icmp *)fin->fin_dp;
  248 
  249                 switch (ic->icmp_type)
  250                 {
  251                 case ICMP_ECHO :
  252                         is->is_icmp.ics_type = ICMP_ECHOREPLY;  /* XXX */
  253                         hv += (is->is_icmp.ics_id = ic->icmp_id);
  254                         hv += (is->is_icmp.ics_seq = ic->icmp_seq);
  255                         break;
  256                 case ICMP_TSTAMP :
  257                 case ICMP_IREQ :
  258                 case ICMP_MASKREQ :
  259                         is->is_icmp.ics_type = ic->icmp_type + 1;
  260                         break;
  261                 default :
  262                         return -1;
  263                 }
  264                 ips_stats.iss_icmp++;
  265                 is->is_age = fr_icmptimeout;
  266                 break;
  267             }
  268         case IPPROTO_TCP :
  269             {
  270                 register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
  271 
  272                 if (tcp->th_flags & TH_RST)
  273                         return NULL;
  274                 /*
  275                  * The endian of the ports doesn't matter, but the ack and
  276                  * sequence numbers do as we do mathematics on them later.
  277                  */
  278                 hv += (is->is_dport = tcp->th_dport);
  279                 hv += (is->is_sport = tcp->th_sport);
  280                 is->is_seq = ntohl(tcp->th_seq);
  281                 is->is_ack = ntohl(tcp->th_ack);
  282                 is->is_swin = ntohs(tcp->th_win);
  283                 is->is_dwin = is->is_swin;      /* start them the same */
  284                 ips_stats.iss_tcp++;
  285                 /*
  286                  * If we're creating state for a starting connection, start the
  287                  * timer on it as we'll never see an error if it fails to
  288                  * connect.
  289                  */
  290                 if ((tcp->th_flags & (TH_SYN|TH_ACK)) == TH_SYN)
  291                         is->is_ack = 0; /* Trumpet WinSock 'ism */
  292                 fr_tcp_age(&is->is_age, is->is_state, ip, fin,
  293                            tcp->th_sport == is->is_sport);
  294                 break;
  295             }
  296         case IPPROTO_UDP :
  297             {
  298                 register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
  299 
  300                 hv += (is->is_dport = tcp->th_dport);
  301                 hv += (is->is_sport = tcp->th_sport);
  302                 ips_stats.iss_udp++;
  303                 is->is_age = fr_udptimeout;
  304                 break;
  305             }
  306         default :
  307                 return -1;
  308         }
  309 
  310         KMALLOC(is, ipstate_t *, sizeof(*is));
  311         if (is == NULL) {
  312                 ips_stats.iss_nomem++;
  313                 return -1;
  314         }
  315         bcopy((char *)&ips, (char *)is, sizeof(*is));
  316         hv %= IPSTATE_SIZE;
  317         MUTEX_ENTER(&ipf_state);
  318 
  319         is->is_pass = pass;
  320         is->is_pkts = 1;
  321         is->is_bytes = ip->ip_len;
  322         /*
  323          * Copy these from the rule itself.
  324          */
  325         is->is_opt = fin->fin_fr->fr_ip.fi_optmsk;
  326         is->is_optmsk = fin->fin_fr->fr_mip.fi_optmsk;
  327         is->is_sec = fin->fin_fr->fr_ip.fi_secmsk;
  328         is->is_secmsk = fin->fin_fr->fr_mip.fi_secmsk;
  329         is->is_auth = fin->fin_fr->fr_ip.fi_auth;
  330         is->is_authmsk = fin->fin_fr->fr_mip.fi_auth;
  331         is->is_flags = fin->fin_fr->fr_ip.fi_fl;
  332         is->is_flags |= fin->fin_fr->fr_mip.fi_fl << 4;
  333         /*
  334          * add into table.
  335          */
  336         is->is_next = ips_table[hv];
  337         ips_table[hv] = is;
  338         if (fin->fin_out) {
  339                 is->is_ifpin = NULL;
  340                 is->is_ifpout = fin->fin_ifp;
  341         } else {
  342                 is->is_ifpin = fin->fin_ifp;
  343                 is->is_ifpout = NULL;
  344         }
  345         if (pass & FR_LOGFIRST)
  346                 is->is_pass &= ~(FR_LOGFIRST|FR_LOG);
  347         ips_num++;
  348 #ifdef  IPFILTER_LOG
  349         ipstate_log(is, ISL_NEW);
  350 #endif
  351         MUTEX_EXIT(&ipf_state);
  352         if (fin->fin_fi.fi_fl & FI_FRAG)
  353                 ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE);
  354         return 0;
  355 }
  356 
  357 
  358 /*
  359  * check to see if a packet with TCP headers fits within the TCP window.
  360  * change timeout depending on whether new packet is a SYN-ACK returning for a
  361  * SYN or a RST or FIN which indicate time to close up shop.
  362  */
  363 int fr_tcpstate(is, fin, ip, tcp)
  364 register ipstate_t *is;
  365 fr_info_t *fin;
  366 ip_t *ip;
  367 tcphdr_t *tcp;
  368 {
  369         register int seqskew, ackskew;
  370         register u_short swin, dwin;
  371         register tcp_seq seq, ack;
  372         int source;
  373 
  374         /*
  375          * Find difference between last checked packet and this packet.
  376          */
  377         seq = ntohl(tcp->th_seq);
  378         ack = ntohl(tcp->th_ack);
  379         source = (ip->ip_src.s_addr == is->is_src.s_addr);
  380 
  381         if (!(tcp->th_flags & TH_ACK))  /* Pretend an ack was sent */
  382                 ack = source ? is->is_ack : is->is_seq;
  383 
  384         if (source) {
  385                 if (!is->is_seq)
  386                         /*
  387                          * Must be an outgoing SYN-ACK in reply to a SYN.
  388                          */
  389                         is->is_seq = seq;
  390                 seqskew = seq - is->is_seq;
  391                 ackskew = ack - is->is_ack;
  392         } else {
  393                 if (!is->is_ack)
  394                         /*
  395                          * Must be a SYN-ACK in reply to a SYN.
  396                          */
  397                         is->is_ack = seq;
  398                 ackskew = seq - is->is_ack;
  399                 seqskew = ack - is->is_seq;
  400         }
  401 
  402         /*
  403          * Make skew values absolute
  404          */
  405         if (seqskew < 0)
  406                 seqskew = -seqskew;
  407         if (ackskew < 0)
  408                 ackskew = -ackskew;
  409 
  410         /*
  411          * If the difference in sequence and ack numbers is within the
  412          * window size of the connection, store these values and match
  413          * the packet.
  414          */
  415         if (source) {
  416                 swin = is->is_swin;
  417                 dwin = is->is_dwin;
  418         } else {
  419                 dwin = is->is_swin;
  420                 swin = is->is_dwin;
  421         }
  422 
  423         if ((seqskew <= dwin) && (ackskew <= swin)) {
  424                 if (source) {
  425                         is->is_seq = seq;
  426                         is->is_ack = ack;
  427                         is->is_swin = ntohs(tcp->th_win);
  428                 } else {
  429                         is->is_seq = ack;
  430                         is->is_ack = seq;
  431                         is->is_dwin = ntohs(tcp->th_win);
  432                 }
  433                 ips_stats.iss_hits++;
  434                 is->is_pkts++;
  435                 is->is_bytes += ip->ip_len;
  436                 /*
  437                  * Nearing end of connection, start timeout.
  438                  */
  439                 fr_tcp_age(&is->is_age, is->is_state, ip, fin, source);
  440                 return 1;
  441         }
  442         return 0;
  443 }
  444 
  445 
  446 static int fr_matchsrcdst(is, src, dst, fin, tcp, sp, dp)
  447 ipstate_t *is;
  448 struct in_addr src, dst;
  449 fr_info_t *fin;
  450 void *tcp;
  451 u_short sp, dp;
  452 {
  453         int ret = 0, rev, out;
  454         void *ifp;
  455 
  456         rev = (is->is_dst.s_addr != dst.s_addr);
  457         ifp = fin->fin_ifp;
  458         out = fin->fin_out;
  459 
  460         if (!rev) {
  461                 if (out) {
  462                         if (!is->is_ifpout)
  463                                 is->is_ifpout = ifp;
  464                 } else {
  465                         if (!is->is_ifpin)
  466                                 is->is_ifpin = ifp;
  467                 }
  468         } else {
  469                 if (out) {
  470                         if (!is->is_ifpin)
  471                                 is->is_ifpin = ifp;
  472                 } else {
  473                         if (!is->is_ifpout)
  474                                 is->is_ifpout = ifp;
  475                 }
  476         }
  477 
  478         if (!rev) {
  479                 if (((out && is->is_ifpout == ifp) ||
  480                      (!out && is->is_ifpin == ifp)) &&
  481                     (is->is_dst.s_addr == dst.s_addr) &&
  482                     (is->is_src.s_addr == src.s_addr) &&
  483                     (!tcp || (sp == is->is_sport) &&
  484                      (dp == is->is_dport))) {
  485                         ret = 1;
  486                 }
  487         } else {
  488                 if (((out && is->is_ifpin == ifp) ||
  489                      (!out && is->is_ifpout == ifp)) &&
  490                     (is->is_dst.s_addr == src.s_addr) &&
  491                     (is->is_src.s_addr == dst.s_addr) &&
  492                     (!tcp || (sp == is->is_dport) &&
  493                      (dp == is->is_sport))) {
  494                         ret = 1;
  495                 }
  496         }
  497 
  498         /*
  499          * Whether or not this should be here, is questionable, but the aim
  500          * is to get this out of the main line.
  501          */
  502         if (ret) {
  503                 if (((fin->fin_fi.fi_optmsk & is->is_optmsk) != is->is_opt) ||
  504                     ((fin->fin_fi.fi_secmsk & is->is_secmsk) != is->is_sec) ||
  505                     ((fin->fin_fi.fi_auth & is->is_authmsk) != is->is_auth) ||
  506                     ((fin->fin_fi.fi_fl & (is->is_flags >> 4)) !=
  507                      (is->is_flags & 0xf)))
  508                         ret = 0;
  509         }
  510         return ret;
  511 }
  512 
  513 
  514 /*
  515  * Check if a packet has a registered state.
  516  */
  517 int fr_checkstate(ip, fin)
  518 ip_t *ip;
  519 fr_info_t *fin;
  520 {
  521         register struct in_addr dst, src;
  522         register ipstate_t *is, **isp;
  523         register u_char pr;
  524         struct icmp *ic;
  525         tcphdr_t *tcp;
  526         u_int hv, hlen, pass;
  527 
  528         if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT))
  529                 return 0;
  530 
  531         hlen = fin->fin_hlen;
  532         tcp = (tcphdr_t *)((char *)ip + hlen);
  533         ic = (struct icmp *)tcp;
  534         hv = (pr = ip->ip_p);
  535         hv += (src.s_addr = ip->ip_src.s_addr);
  536         hv += (dst.s_addr = ip->ip_dst.s_addr);
  537 
  538         /*
  539          * Search the hash table for matching packet header info.
  540          */
  541         switch (ip->ip_p)
  542         {
  543         case IPPROTO_ICMP :
  544                 hv += ic->icmp_id;
  545                 hv += ic->icmp_seq;
  546                 hv %= IPSTATE_SIZE;
  547                 MUTEX_ENTER(&ipf_state);
  548                 for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next)
  549                         if ((is->is_p == pr) &&
  550                             (ic->icmp_id == is->is_icmp.ics_id) &&
  551                             (ic->icmp_seq == is->is_icmp.ics_seq) &&
  552                             fr_matchsrcdst(is, src, dst, fin, NULL, 0, 0)) {
  553                                 if (is->is_icmp.ics_type != ic->icmp_type)
  554                                         continue;
  555                                 is->is_age = fr_icmptimeout;
  556                                 is->is_pkts++;
  557                                 is->is_bytes += ip->ip_len;
  558                                 ips_stats.iss_hits++;
  559                                 pass = is->is_pass;
  560                                 MUTEX_EXIT(&ipf_state);
  561                                 return pass;
  562                         }
  563                 MUTEX_EXIT(&ipf_state);
  564                 break;
  565         case IPPROTO_TCP :
  566             {
  567                 register u_short dport = tcp->th_dport, sport = tcp->th_sport;
  568 
  569                 hv += dport;
  570                 hv += sport;
  571                 hv %= IPSTATE_SIZE;
  572                 MUTEX_ENTER(&ipf_state);
  573                 for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next)
  574                         if ((is->is_p == pr) &&
  575                             fr_matchsrcdst(is, src, dst, fin, tcp,
  576                                            sport, dport)) {
  577                                 if (fr_tcpstate(is, fin, ip, tcp)) {
  578                                         pass = is->is_pass;
  579 #ifdef  _KERNEL
  580                                         MUTEX_EXIT(&ipf_state);
  581 #else
  582 
  583                                         if (tcp->th_flags & TCP_CLOSE) {
  584                                                 *isp = is->is_next;
  585                                                 isp = &ips_table[hv];
  586                                                 KFREE(is);
  587                                         }
  588 #endif
  589                                         return pass;
  590                                 }
  591                         }
  592                 MUTEX_EXIT(&ipf_state);
  593                 break;
  594             }
  595         case IPPROTO_UDP :
  596             {
  597                 register u_short dport = tcp->th_dport, sport = tcp->th_sport;
  598 
  599                 hv += dport;
  600                 hv += sport;
  601                 hv %= IPSTATE_SIZE;
  602                 /*
  603                  * Nothing else to match on but ports. and IP#'s
  604                  */
  605                 MUTEX_ENTER(&ipf_state);
  606                 for (is = ips_table[hv]; is; is = is->is_next)
  607                         if ((is->is_p == pr) &&
  608                             fr_matchsrcdst(is, src, dst, fin,
  609                                            tcp, sport, dport)) {
  610                                 ips_stats.iss_hits++;
  611                                 is->is_pkts++;
  612                                 is->is_bytes += ip->ip_len;
  613                                 is->is_age = fr_udptimeout;
  614                                 pass = is->is_pass;
  615                                 MUTEX_EXIT(&ipf_state);
  616                                 return pass;
  617                         }
  618                 MUTEX_EXIT(&ipf_state);
  619                 break;
  620             }
  621         default :
  622                 break;
  623         }
  624         ips_stats.iss_miss++;
  625         return 0;
  626 }
  627 
  628 
  629 /*
  630  * Free memory in use by all state info. kept.
  631  */
  632 void fr_stateunload()
  633 {
  634         register int i;
  635         register ipstate_t *is, **isp;
  636 
  637         MUTEX_ENTER(&ipf_state);
  638         for (i = 0; i < IPSTATE_SIZE; i++)
  639                 for (isp = &ips_table[i]; (is = *isp); ) {
  640                         *isp = is->is_next;
  641                         KFREE(is);
  642                 }
  643         MUTEX_EXIT(&ipf_state);
  644 }
  645 
  646 
  647 /*
  648  * Slowly expire held state for thingslike UDP and ICMP.  Timeouts are set
  649  * in expectation of this being called twice per second.
  650  */
  651 void fr_timeoutstate()
  652 {
  653         register int i;
  654         register ipstate_t *is, **isp;
  655 #if defined(_KERNEL) && !SOLARIS
  656         int s;
  657 #endif
  658 
  659         SPL_NET(s);
  660         MUTEX_ENTER(&ipf_state);
  661         for (i = 0; i < IPSTATE_SIZE; i++)
  662                 for (isp = &ips_table[i]; (is = *isp); )
  663                         if (is->is_age && !--is->is_age) {
  664                                 *isp = is->is_next;
  665                                 if (is->is_p == IPPROTO_TCP)
  666                                         ips_stats.iss_fin++;
  667                                 else
  668                                         ips_stats.iss_expire++;
  669 #ifdef  IPFILTER_LOG
  670                                 ipstate_log(is, ISL_EXPIRE);
  671 #endif
  672                                 KFREE(is);
  673                                 ips_num--;
  674                         } else
  675                                 isp = &is->is_next;
  676         MUTEX_EXIT(&ipf_state);
  677         SPL_X(s);
  678 }
  679 
  680 
  681 /*
  682  * Original idea freom Pradeep Krishnan for use primarily with NAT code.
  683  * (pkrishna@netcom.com)
  684  */
  685 void fr_tcp_age(age, state, ip, fin, dir)
  686 u_long *age;
  687 u_char *state;
  688 ip_t *ip;
  689 fr_info_t *fin;
  690 int dir;
  691 {
  692         tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
  693         u_char flags = tcp->th_flags;
  694         int dlen, ostate;
  695 
  696         ostate = state[1 - dir];
  697 
  698         dlen = ip->ip_len - fin->fin_hlen - (tcp->th_off << 2);
  699 
  700         if (flags & TH_RST) {
  701                 if (!(tcp->th_flags & TH_PUSH) && !dlen) {
  702                         *age = fr_tcpclosed;
  703                         state[dir] = TCPS_CLOSED;
  704                 } else {
  705                         *age = fr_tcpclosewait;
  706                         state[dir] = TCPS_CLOSE_WAIT;
  707                 }
  708                 return;
  709         }
  710 
  711         *age = fr_tcptimeout; /* 1 min */
  712 
  713         switch(state[dir])
  714         {
  715         case TCPS_FIN_WAIT_2:
  716         case TCPS_CLOSED:
  717                 if ((flags & TH_OPENING) == TH_OPENING)
  718                         state[dir] = TCPS_SYN_RECEIVED;
  719                 else if (flags & TH_SYN)
  720                         state[dir] = TCPS_SYN_SENT;
  721                 break;
  722         case TCPS_SYN_RECEIVED:
  723                 if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) {
  724                         state[dir] = TCPS_ESTABLISHED;
  725                         *age = fr_tcpidletimeout;
  726                 }
  727                 break;
  728         case TCPS_SYN_SENT:
  729                 if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) {
  730                         state[dir] = TCPS_ESTABLISHED;
  731                         *age = fr_tcpidletimeout;
  732                 }
  733                 break;
  734         case TCPS_ESTABLISHED:
  735                 if (flags & TH_FIN) {
  736                         state[dir] = TCPS_CLOSE_WAIT;
  737                         if (!(flags & TH_PUSH) && !dlen &&
  738                             ostate > TCPS_ESTABLISHED)
  739                                 *age  = fr_tcplastack;
  740                         else
  741                                 *age  = fr_tcpclosewait;
  742                 } else
  743                         *age = fr_tcpidletimeout;
  744                 break;
  745         case TCPS_CLOSE_WAIT:
  746                 if ((flags & TH_FIN) && !(flags & TH_PUSH) && !dlen &&
  747                     ostate > TCPS_ESTABLISHED) {
  748                         *age  = fr_tcplastack;
  749                         state[dir] = TCPS_LAST_ACK;
  750                 } else
  751                         *age  = fr_tcpclosewait;
  752                 break;
  753         case TCPS_LAST_ACK:
  754                 if (flags & TH_ACK) {
  755                         state[dir] = TCPS_FIN_WAIT_2;
  756                         if (!(flags & TH_PUSH) && !dlen &&
  757                             ostate > TCPS_ESTABLISHED)
  758                                 *age  = fr_tcplastack;
  759                         else {
  760                                 *age  = fr_tcpclosewait;
  761                                 state[dir] = TCPS_CLOSE_WAIT;
  762                         }
  763                 }
  764                 break;
  765         }
  766 }
  767 
  768 
  769 #ifdef  IPFILTER_LOG
  770 void ipstate_log(is, type)
  771 struct ipstate *is;
  772 u_short type;
  773 {
  774         struct  ipslog  ipsl;
  775         void *items[1];
  776         size_t sizes[1];
  777         int types[1];
  778 
  779         ipsl.isl_pkts = is->is_pkts;
  780         ipsl.isl_bytes = is->is_bytes;
  781         ipsl.isl_src = is->is_src;
  782         ipsl.isl_dst = is->is_dst;
  783         ipsl.isl_p = is->is_p;
  784         ipsl.isl_flags = is->is_flags;
  785         ipsl.isl_type = type;
  786         if (ipsl.isl_p == IPPROTO_TCP || ipsl.isl_p == IPPROTO_UDP) {
  787                 ipsl.isl_sport = is->is_sport;
  788                 ipsl.isl_dport = is->is_dport;
  789         } else if (ipsl.isl_p == IPPROTO_ICMP)
  790                 ipsl.isl_itype = is->is_icmp.ics_type;
  791         else {
  792                 ipsl.isl_ps.isl_filler[0] = 0;
  793                 ipsl.isl_ps.isl_filler[1] = 0;
  794         }
  795         items[0] = &ipsl;
  796         sizes[0] = sizeof(ipsl);
  797         types[0] = 0;
  798 
  799         (void) ipllog(IPL_LOGSTATE, 0, items, sizes, types, 1);
  800 }
  801 #endif

Cache object: f66506a0eef42976b7221263320f211e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.