v2.4.9.9 -> v2.4.9.10
[opensuse:kernel.git] / net / ipv4 / netfilter / ipchains_core.c
1 /* Minor modifications to fit on compatibility framework:
2    Rusty.Russell@rustcorp.com.au
3 */
4
5 /*
6  * This code is heavily based on the code on the old ip_fw.c code; see below for
7  * copyrights and attributions of the old code.  This code is basically GPL.
8  *
9  * 15-Aug-1997: Major changes to allow graphs for firewall rules.
10  *              Paul Russell <Paul.Russell@rustcorp.com.au> and
11  *              Michael Neuling <Michael.Neuling@rustcorp.com.au>
12  * 24-Aug-1997: Generalised protocol handling (not just TCP/UDP/ICMP).
13  *              Added explicit RETURN from chains.
14  *              Removed TOS mangling (done in ipchains 1.0.1).
15  *              Fixed read & reset bug by reworking proc handling.
16  *              Paul Russell <Paul.Russell@rustcorp.com.au>
17  * 28-Sep-1997: Added packet marking for net sched code.
18  *              Removed fw_via comparisons: all done on device name now,
19  *              similar to changes in ip_fw.c in DaveM's CVS970924 tree.
20  *              Paul Russell <Paul.Russell@rustcorp.com.au>
21  * 2-Nov-1997:  Moved types across to __u16, etc.
22  *              Added inverse flags.
23  *              Fixed fragment bug (in args to port_match).
24  *              Changed mark to only one flag (MARKABS).
25  * 21-Nov-1997: Added ability to test ICMP code.
26  * 19-Jan-1998: Added wildcard interfaces.
27  * 6-Feb-1998:  Merged 2.0 and 2.1 versions.
28  *              Initialised ip_masq for 2.0.x version.
29  *              Added explicit NETLINK option for 2.1.x version.
30  *              Added packet and byte counters for policy matches.
31  * 26-Feb-1998: Fixed race conditions, added SMP support.
32  * 18-Mar-1998: Fix SMP, fix race condition fix.
33  * 1-May-1998:  Remove caching of device pointer.
34  * 12-May-1998: Allow tiny fragment case for TCP/UDP.
35  * 15-May-1998: Treat short packets as fragments, don't just block.
36  * 3-Jan-1999:  Fixed serious procfs security hole -- users should never
37  *              be allowed to view the chains!
38  *              Marc Santoro <ultima@snicker.emoti.com>
39  * 29-Jan-1999: Locally generated bogus IPs dealt with, rather than crash
40  *              during dump_packet. --RR.
41  * 19-May-1999: Star Wars: The Phantom Menace opened.  Rule num
42  *              printed in log (modified from Michael Hasenstein's patch).
43  *              Added SYN in log message. --RR
44  * 23-Jul-1999: Fixed small fragment security exposure opened on 15-May-1998.
45  *              John McDonald <jm@dataprotect.com>
46  *              Thomas Lopatic <tl@dataprotect.com>
47  */
48
49 /*
50  *
51  * The origina Linux port was done Alan Cox, with changes/fixes from
52  * Pauline Middlelink, Jos Vos, Thomas Quinot, Wouter Gadeyne, Juan
53  * Jose Ciarlante, Bernd Eckenfels, Keith Owens and others.
54  *
55  * Copyright from the original FreeBSD version follows:
56  *
57  * Copyright (c) 1993 Daniel Boulet
58  * Copyright (c) 1994 Ugen J.S.Antsilevich
59  *
60  * Redistribution and use in source forms, with and without modification,
61  * are permitted provided that this entire comment appears intact.
62  *
63  * Redistribution in binary form may occur without any restrictions.
64  * Obviously, it would be nice if you gave credit where credit is due
65  * but requiring it would be too onerous.
66  *
67  * This software is provided ``AS IS'' without any warranties of any kind.  */
68
69 #include <linux/config.h>
70
71 #include <asm/uaccess.h>
72 #include <asm/system.h>
73 #include <linux/types.h>
74 #include <linux/sched.h>
75 #include <linux/string.h>
76 #include <linux/errno.h>
77 #include <linux/module.h>
78
79 #include <linux/socket.h>
80 #include <linux/sockios.h>
81 #include <linux/in.h>
82 #include <linux/inet.h>
83 #include <linux/netdevice.h>
84 #include <linux/icmp.h>
85 #include <linux/udp.h>
86 #include <net/ip.h>
87 #include <net/protocol.h>
88 #include <net/route.h>
89 #include <net/tcp.h>
90 #include <net/udp.h>
91 #include <net/sock.h>
92 #include <net/icmp.h>
93 #include <linux/netlink.h>
94 #include <linux/netfilter.h>
95 #include <linux/netfilter_ipv4/compat_firewall.h>
96 #include <linux/netfilter_ipv4/ipchains_core.h>
97
98 #include <net/checksum.h>
99 #include <linux/proc_fs.h>
100 #include <linux/stat.h>
101
102 /* Understanding locking in this code: (thanks to Alan Cox for using
103  * little words to explain this to me). -- PR
104  *
105  * In UP, there can be two packets traversing the chains:
106  * 1) A packet from the current userspace context
107  * 2) A packet off the bh handlers (timer or net).
108  *
109  * For SMP (kernel v2.1+), multiply this by # CPUs.
110  *
111  * [Note that this in not correct for 2.2 - because the socket code always
112  *  uses lock_kernel() to serialize, and bottom halves (timers and net_bhs)
113  *  only run on one CPU at a time.  This will probably change for 2.3.
114  *  It is still good to use spinlocks because that avoids the global cli()
115  *  for updating the tables, which is rather costly in SMP kernels -AK]
116  *
117  * This means counters and backchains can get corrupted if no precautions
118  * are taken.
119  *
120  * To actually alter a chain on UP, we need only do a cli(), as this will
121  * stop a bh handler firing, as we are in the current userspace context
122  * (coming from a setsockopt()).
123  *
124  * On SMP, we need a write_lock_irqsave(), which is a simple cli() in
125  * UP.
126  *
127  * For backchains and counters, we use an array, indexed by
128  * [cpu_number_map[smp_processor_id()]*2 + !in_interrupt()]; the array is of
129  * size [smp_num_cpus*2].  For v2.0, smp_num_cpus is effectively 1.  So,
130  * confident of uniqueness, we modify counters even though we only
131  * have a read lock (to read the counters, you need a write lock,
132  * though).  */
133
134 /* Why I didn't use straight locking... -- PR
135  *
136  * The backchains can be separated out of the ip_chains structure, and
137  * allocated as needed inside ip_fw_check().
138  *
139  * The counters, however, can't.  Trying to lock these means blocking
140  * interrupts every time we want to access them.  This would suck HARD
141  * performance-wise.  Not locking them leads to possible corruption,
142  * made worse on 32-bit machines (counters are 64-bit).  */
143
144 /*#define DEBUG_IP_FIREWALL*/
145 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
146 /*#define DEBUG_IP_FIREWALL_USER*/
147 /*#define DEBUG_IP_FIREWALL_LOCKING*/
148
149 #if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
150 static struct sock *ipfwsk;
151 #endif
152
153 #ifdef CONFIG_SMP
154 #define SLOT_NUMBER() (cpu_number_map(smp_processor_id())*2 + !in_interrupt())
155 #else /* !SMP */
156 #define SLOT_NUMBER() (!in_interrupt())
157 #endif /* CONFIG_SMP */
158 #define NUM_SLOTS (smp_num_cpus*2)
159
160 #define SIZEOF_STRUCT_IP_CHAIN (sizeof(struct ip_chain) \
161                                 + NUM_SLOTS*sizeof(struct ip_reent))
162 #define SIZEOF_STRUCT_IP_FW_KERNEL (sizeof(struct ip_fwkernel) \
163                                     + NUM_SLOTS*sizeof(struct ip_counters))
164
165 #ifdef DEBUG_IP_FIREWALL_LOCKING
166 static unsigned int fwc_rlocks, fwc_wlocks;
167 #define FWC_DEBUG_LOCK(d)                       \
168 do {                                            \
169         FWC_DONT_HAVE_LOCK(d);                  \
170         d |= (1 << SLOT_NUMBER());              \
171 } while (0)
172
173 #define FWC_DEBUG_UNLOCK(d)                     \
174 do {                                            \
175         FWC_HAVE_LOCK(d);                       \
176         d &= ~(1 << SLOT_NUMBER());             \
177 } while (0)
178
179 #define FWC_DONT_HAVE_LOCK(d)                                   \
180 do {                                                            \
181         if ((d) & (1 << SLOT_NUMBER()))                         \
182                 printk("%s:%i: Got lock on %i already!\n",      \
183                        __FILE__, __LINE__, SLOT_NUMBER());      \
184 } while(0)
185
186 #define FWC_HAVE_LOCK(d)                                \
187 do {                                                    \
188         if (!((d) & (1 << SLOT_NUMBER())))              \
189         printk("%s:%i:No lock on %i!\n",                \
190                __FILE__, __LINE__, SLOT_NUMBER());      \
191 } while (0)
192
193 #else
194 #define FWC_DEBUG_LOCK(d) do { } while(0)
195 #define FWC_DEBUG_UNLOCK(d) do { } while(0)
196 #define FWC_DONT_HAVE_LOCK(d) do { } while(0)
197 #define FWC_HAVE_LOCK(d) do { } while(0)
198 #endif /*DEBUG_IP_FIRWALL_LOCKING*/
199
200 #define FWC_READ_LOCK(l) do { FWC_DEBUG_LOCK(fwc_rlocks); read_lock(l); } while (0)
201 #define FWC_WRITE_LOCK(l) do { FWC_DEBUG_LOCK(fwc_wlocks); write_lock(l); } while (0)
202 #define FWC_READ_LOCK_IRQ(l,f) do { FWC_DEBUG_LOCK(fwc_rlocks); read_lock_irqsave(l,f); } while (0)
203 #define FWC_WRITE_LOCK_IRQ(l,f) do { FWC_DEBUG_LOCK(fwc_wlocks); write_lock_irqsave(l,f); } while (0)
204 #define FWC_READ_UNLOCK(l) do { FWC_DEBUG_UNLOCK(fwc_rlocks); read_unlock(l); } while (0)
205 #define FWC_WRITE_UNLOCK(l) do { FWC_DEBUG_UNLOCK(fwc_wlocks); write_unlock(l); } while (0)
206 #define FWC_READ_UNLOCK_IRQ(l,f) do { FWC_DEBUG_UNLOCK(fwc_rlocks); read_unlock_irqrestore(l,f); } while (0)
207 #define FWC_WRITE_UNLOCK_IRQ(l,f) do { FWC_DEBUG_UNLOCK(fwc_wlocks); write_unlock_irqrestore(l,f); } while (0)
208
209 struct ip_chain;
210
211 struct ip_counters
212 {
213         __u64 pcnt, bcnt;                       /* Packet and byte counters */
214 };
215
216 struct ip_fwkernel
217 {
218         struct ip_fw ipfw;
219         struct ip_fwkernel *next;       /* where to go next if current
220                                          * rule doesn't match */
221         struct ip_chain *branch;        /* which branch to jump to if
222                                          * current rule matches */
223         int simplebranch;               /* Use this if branch == NULL */
224         struct ip_counters counters[0]; /* Actually several of these */
225 };
226
227 struct ip_reent
228 {
229         struct ip_chain *prevchain;     /* Pointer to referencing chain */
230         struct ip_fwkernel *prevrule;   /* Pointer to referencing rule */
231         struct ip_counters counters;
232 };
233
234 struct ip_chain
235 {
236         ip_chainlabel label;        /* Defines the label for each block */
237         struct ip_chain *next;      /* Pointer to next block */
238         struct ip_fwkernel *chain;  /* Pointer to first rule in block */
239         __u32 refcount;             /* Number of refernces to block */
240         int policy;                 /* Default rule for chain.  Only *
241                                      * used in built in chains */
242         struct ip_reent reent[0];   /* Actually several of these */
243 };
244
245 /*
246  *      Implement IP packet firewall
247  */
248
249 #ifdef DEBUG_IP_FIREWALL
250 #define dprintf(format, args...)  printk(format , ## args)
251 #else
252 #define dprintf(format, args...)
253 #endif
254
255 #ifdef DEBUG_IP_FIREWALL_USER
256 #define duprintf(format, args...) printk(format , ## args)
257 #else
258 #define duprintf(format, args...)
259 #endif
260
261 /* Lock around ip_fw_chains linked list structure */
262 rwlock_t ip_fw_lock = RW_LOCK_UNLOCKED;
263
264 /* Head of linked list of fw rules */
265 static struct ip_chain *ip_fw_chains;
266
267 #define IP_FW_INPUT_CHAIN ip_fw_chains
268 #define IP_FW_FORWARD_CHAIN (ip_fw_chains->next)
269 #define IP_FW_OUTPUT_CHAIN (ip_fw_chains->next->next)
270
271 /* Returns 1 if the port is matched by the range, 0 otherwise */
272 extern inline int port_match(__u16 min, __u16 max, __u16 port,
273                              int frag, int invert)
274 {
275         if (frag) /* Fragments fail ANY port test. */
276                 return (min == 0 && max == 0xFFFF);
277         else return (port >= min && port <= max) ^ invert;
278 }
279
280 /* Returns whether matches rule or not. */
281 static int ip_rule_match(struct ip_fwkernel *f,
282                          const char *ifname,
283                          struct iphdr *ip,
284                          char tcpsyn,
285                          __u16 src_port, __u16 dst_port,
286                          char isfrag)
287 {
288 #define FWINV(bool,invflg) ((bool) ^ !!(f->ipfw.fw_invflg & invflg))
289         /*
290          *      This is a bit simpler as we don't have to walk
291          *      an interface chain as you do in BSD - same logic
292          *      however.
293          */
294
295         if (FWINV((ip->saddr&f->ipfw.fw_smsk.s_addr) != f->ipfw.fw_src.s_addr,
296                   IP_FW_INV_SRCIP)
297             || FWINV((ip->daddr&f->ipfw.fw_dmsk.s_addr)!=f->ipfw.fw_dst.s_addr,
298                      IP_FW_INV_DSTIP)) {
299                 dprintf("Source or dest mismatch.\n");
300
301                 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
302                         f->ipfw.fw_smsk.s_addr, f->ipfw.fw_src.s_addr,
303                         f->ipfw.fw_invflg & IP_FW_INV_SRCIP ? " (INV)" : "");
304                 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
305                         f->ipfw.fw_dmsk.s_addr, f->ipfw.fw_dst.s_addr,
306                         f->ipfw.fw_invflg & IP_FW_INV_DSTIP ? " (INV)" : "");
307                 return 0;
308         }
309
310         /*
311          *      Look for a VIA device match
312          */
313         if (f->ipfw.fw_flg & IP_FW_F_WILDIF) {
314             if (FWINV(strncmp(ifname, f->ipfw.fw_vianame,
315                               strlen(f->ipfw.fw_vianame)) != 0,
316                       IP_FW_INV_VIA)) {
317                 dprintf("Wildcard interface mismatch.%s\n",
318                         f->ipfw.fw_invflg & IP_FW_INV_VIA ? " (INV)" : "");
319                 return 0;       /* Mismatch */
320             }
321         }
322         else if (FWINV(strcmp(ifname, f->ipfw.fw_vianame) != 0,
323                        IP_FW_INV_VIA)) {
324             dprintf("Interface name does not match.%s\n",
325                     f->ipfw.fw_invflg & IP_FW_INV_VIA
326                     ? " (INV)" : "");
327             return 0;   /* Mismatch */
328         }
329
330         /*
331          *      Ok the chain addresses match.
332          */
333
334         /* If we have a fragment rule but the packet is not a fragment
335          * the we return zero */
336         if (FWINV((f->ipfw.fw_flg&IP_FW_F_FRAG) && !isfrag, IP_FW_INV_FRAG)) {
337                 dprintf("Fragment rule but not fragment.%s\n",
338                         f->ipfw.fw_invflg & IP_FW_INV_FRAG ? " (INV)" : "");
339                 return 0;
340         }
341
342         /* Fragment NEVER passes a SYN test, even an inverted one. */
343         if (FWINV((f->ipfw.fw_flg&IP_FW_F_TCPSYN) && !tcpsyn, IP_FW_INV_SYN)
344             || (isfrag && (f->ipfw.fw_flg&IP_FW_F_TCPSYN))) {
345                 dprintf("Rule requires SYN and packet has no SYN.%s\n",
346                         f->ipfw.fw_invflg & IP_FW_INV_SYN ? " (INV)" : "");
347                 return 0;
348         }
349
350         if (f->ipfw.fw_proto) {
351                 /*
352                  *      Specific firewall - packet's protocol
353                  *      must match firewall's.
354                  */
355
356                 if (FWINV(ip->protocol!=f->ipfw.fw_proto, IP_FW_INV_PROTO)) {
357                         dprintf("Packet protocol %hi does not match %hi.%s\n",
358                                 ip->protocol, f->ipfw.fw_proto,
359                                 f->ipfw.fw_invflg&IP_FW_INV_PROTO ? " (INV)":"");
360                         return 0;
361                 }
362
363                 /* For non TCP/UDP/ICMP, port range is max anyway. */
364                 if (!port_match(f->ipfw.fw_spts[0],
365                                 f->ipfw.fw_spts[1],
366                                 src_port, isfrag,
367                                 !!(f->ipfw.fw_invflg&IP_FW_INV_SRCPT))
368                     || !port_match(f->ipfw.fw_dpts[0],
369                                    f->ipfw.fw_dpts[1],
370                                    dst_port, isfrag,
371                                    !!(f->ipfw.fw_invflg
372                                       &IP_FW_INV_DSTPT))) {
373                     dprintf("Port match failed.\n");
374                     return 0;
375                 }
376         }
377
378         dprintf("Match succeeded.\n");
379         return 1;
380 }
381
382 static const char *branchname(struct ip_chain *branch,int simplebranch)
383 {
384         if (branch)
385                 return branch->label;
386         switch (simplebranch)
387         {
388         case FW_BLOCK: return IP_FW_LABEL_BLOCK;
389         case FW_ACCEPT: return IP_FW_LABEL_ACCEPT;
390         case FW_REJECT: return IP_FW_LABEL_REJECT;
391         case FW_REDIRECT: return IP_FW_LABEL_REDIRECT;
392         case FW_MASQUERADE: return IP_FW_LABEL_MASQUERADE;
393         case FW_SKIP: return "-";
394         case FW_SKIP+1: return IP_FW_LABEL_RETURN;
395         default:
396                 return "UNKNOWN";
397         }
398 }
399
400 /*
401  * VERY ugly piece of code which actually
402  * makes kernel printf for matching packets...
403  */
404 static void dump_packet(const struct iphdr *ip,
405                         const char *ifname,
406                         struct ip_fwkernel *f,
407                         const ip_chainlabel chainlabel,
408                         __u16 src_port,
409                         __u16 dst_port,
410                         unsigned int count,
411                         int syn)
412 {
413         __u32 *opt = (__u32 *) (ip + 1);
414         int opti;
415
416         if (f) {
417                 printk(KERN_INFO "Packet log: %s ",chainlabel);
418                 printk("%s ",branchname(f->branch,f->simplebranch));
419                 if (f->simplebranch==FW_REDIRECT)
420                         printk("%d ",f->ipfw.fw_redirpt);
421         }
422
423         printk("%s PROTO=%d %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu"
424                " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu",
425                ifname, ip->protocol, NIPQUAD(ip->saddr),
426                src_port, NIPQUAD(ip->daddr),
427                dst_port,
428                ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
429                ntohs(ip->frag_off), ip->ttl);
430
431         for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
432                 printk(" O=0x%8.8X", *opt++);
433         printk(" %s(#%d)\n", syn ? "SYN " : /* "PENANCE" */ "", count);
434 }
435
436 /* function for checking chain labels for user space. */
437 static int check_label(ip_chainlabel label)
438 {
439         unsigned int i;
440         /* strlen must be < IP_FW_MAX_LABEL_LENGTH. */
441         for (i = 0; i < IP_FW_MAX_LABEL_LENGTH + 1; i++)
442                 if (label[i] == '\0') return 1;
443
444         return 0;
445 }
446
447 /*      This function returns a pointer to the first chain with a label
448  *      that matches the one given. */
449 static struct ip_chain *find_label(ip_chainlabel label)
450 {
451         struct ip_chain *tmp;
452         FWC_HAVE_LOCK(fwc_rlocks | fwc_wlocks);
453         for (tmp = ip_fw_chains; tmp; tmp = tmp->next)
454                 if (strcmp(tmp->label,label) == 0)
455                         break;
456         return tmp;
457 }
458
459 /* This function returns a boolean which when true sets answer to one
460    of the FW_*. */
461 static int find_special(ip_chainlabel label, int *answer)
462 {
463         if (label[0] == '\0') {
464                 *answer = FW_SKIP; /* => pass-through rule */
465                 return 1;
466         } else if (strcmp(label,IP_FW_LABEL_ACCEPT) == 0) {
467                 *answer = FW_ACCEPT;
468                 return 1;
469         } else if (strcmp(label,IP_FW_LABEL_BLOCK) == 0) {
470                 *answer = FW_BLOCK;
471                 return 1;
472         } else if (strcmp(label,IP_FW_LABEL_REJECT) == 0) {
473                 *answer = FW_REJECT;
474                 return 1;
475         } else if (strcmp(label,IP_FW_LABEL_REDIRECT) == 0) {
476                 *answer = FW_REDIRECT;
477                 return 1;
478         } else if (strcmp(label,IP_FW_LABEL_MASQUERADE) == 0) {
479                 *answer = FW_MASQUERADE;
480                 return 1;
481         } else if (strcmp(label, IP_FW_LABEL_RETURN) == 0) {
482                 *answer = FW_SKIP+1;
483                 return 1;
484         } else {
485                 return 0;
486         }
487 }
488
489 /* This function cleans up the prevchain and prevrule.  If the verbose
490  * flag is set then he names of the chains will be printed as it
491  * cleans up.  */
492 static void cleanup(struct ip_chain *chain,
493                     const int verbose,
494                     unsigned int slot)
495 {
496         struct ip_chain *tmpchain = chain->reent[slot].prevchain;
497         if (verbose)
498                 printk(KERN_ERR "Chain backtrace: ");
499         while (tmpchain) {
500                 if (verbose)
501                         printk("%s<-",chain->label);
502                 chain->reent[slot].prevchain = NULL;
503                 chain = tmpchain;
504                 tmpchain = chain->reent[slot].prevchain;
505         }
506         if (verbose)
507                 printk("%s\n",chain->label);
508 }
509
510 static inline int
511 ip_fw_domatch(struct ip_fwkernel *f,
512               struct iphdr *ip,
513               const char *rif,
514               const ip_chainlabel label,
515               struct sk_buff *skb,
516               unsigned int slot,
517               __u16 src_port, __u16 dst_port,
518               unsigned int count,
519               int tcpsyn)
520 {
521         f->counters[slot].bcnt+=ntohs(ip->tot_len);
522         f->counters[slot].pcnt++;
523         if (f->ipfw.fw_flg & IP_FW_F_PRN) {
524                 dump_packet(ip,rif,f,label,src_port,dst_port,count,tcpsyn);
525         }
526         ip->tos = (ip->tos & f->ipfw.fw_tosand) ^ f->ipfw.fw_tosxor;
527
528 /* This functionality is useless in stock 2.0.x series, but we don't
529  * discard the mark thing altogether, to avoid breaking ipchains (and,
530  * more importantly, the ipfwadm wrapper) --PR */
531         if (f->ipfw.fw_flg & IP_FW_F_MARKABS) {
532                 skb->nfmark = f->ipfw.fw_mark;
533         } else {
534                 skb->nfmark += f->ipfw.fw_mark;
535         }
536         if (f->ipfw.fw_flg & IP_FW_F_NETLINK) {
537 #if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
538                 size_t len = min_t(unsigned int, f->ipfw.fw_outputsize, ntohs(ip->tot_len))
539                         + sizeof(__u32) + sizeof(skb->nfmark) + IFNAMSIZ;
540                 struct sk_buff *outskb=alloc_skb(len, GFP_ATOMIC);
541
542                 duprintf("Sending packet out NETLINK (length = %u).\n",
543                          (unsigned int)len);
544                 if (outskb) {
545                         /* Prepend length, mark & interface */
546                         skb_put(outskb, len);
547                         *((__u32 *)outskb->data) = (__u32)len;
548                         *((__u32 *)(outskb->data+sizeof(__u32))) = skb->nfmark;
549                         strcpy(outskb->data+sizeof(__u32)*2, rif);
550                         memcpy(outskb->data+sizeof(__u32)*2+IFNAMSIZ, ip,
551                                len-(sizeof(__u32)*2+IFNAMSIZ));
552                         netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_KERNEL);
553                 }
554                 else {
555 #endif
556                         if (net_ratelimit())
557                                 printk(KERN_WARNING "ip_fw: packet drop due to "
558                                        "netlink failure\n");
559                         return 0;
560 #if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
561                 }
562 #endif
563         }
564         return 1;
565 }
566
567 /*
568  *      Returns one of the generic firewall policies, like FW_ACCEPT.
569  *
570  *      The testing is either false for normal firewall mode or true for
571  *      user checking mode (counters are not updated, TOS & mark not done).
572  */
573 static int
574 ip_fw_check(struct iphdr *ip,
575             const char *rif,
576             __u16 *redirport,
577             struct ip_chain *chain,
578             struct sk_buff *skb,
579             unsigned int slot,
580             int testing)
581 {
582         struct tcphdr           *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);
583         struct udphdr           *udp=(struct udphdr *)((__u32 *)ip+ip->ihl);
584         struct icmphdr          *icmp=(struct icmphdr *)((__u32 *)ip+ip->ihl);
585         __u32                   src, dst;
586         __u16                   src_port = 0xFFFF, dst_port = 0xFFFF;
587         char                    tcpsyn=0;
588         __u16                   offset;
589         unsigned char           oldtos;
590         struct ip_fwkernel      *f;
591         int                     ret = FW_SKIP+2;
592         unsigned int            count;
593
594         /* We handle fragments by dealing with the first fragment as
595          * if it was a normal packet.  All other fragments are treated
596          * normally, except that they will NEVER match rules that ask
597          * things we don't know, ie. tcp syn flag or ports).  If the
598          * rule is also a fragment-specific rule, non-fragments won't
599          * match it. */
600
601         offset = ntohs(ip->frag_off) & IP_OFFSET;
602
603         /*
604          *      Don't allow a fragment of TCP 8 bytes in. Nobody
605          *      normal causes this. Its a cracker trying to break
606          *      in by doing a flag overwrite to pass the direction
607          *      checks.
608          */
609         if (offset == 1 && ip->protocol == IPPROTO_TCP) {
610                 if (!testing && net_ratelimit()) {
611                         printk("Suspect TCP fragment.\n");
612                         dump_packet(ip,rif,NULL,NULL,0,0,0,0);
613                 }
614                 return FW_BLOCK;
615         }
616
617         /* If we can't investigate ports, treat as fragment.  It's
618          * either a trucated whole packet, or a truncated first
619          * fragment, or a TCP first fragment of length 8-15, in which
620          * case the above rule stops reassembly.
621          */
622         if (offset == 0) {
623                 unsigned int size_req;
624                 switch (ip->protocol) {
625                 case IPPROTO_TCP:
626                         /* Don't care about things past flags word */
627                         size_req = 16;
628                         break;
629
630                 case IPPROTO_UDP:
631                 case IPPROTO_ICMP:
632                         size_req = 8;
633                         break;
634
635                 default:
636                         size_req = 0;
637                 }
638
639                 /* If it is a truncated first fragment then it can be
640                  * used to rewrite port information, and thus should
641                  * be blocked.
642                  */
643                 if (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req) {
644                         if (!testing && net_ratelimit()) {
645                                 printk("Suspect short first fragment.\n");
646                                 dump_packet(ip,rif,NULL,NULL,0,0,0,0);
647                         }
648                         return FW_BLOCK;
649                 }
650         }
651
652         src = ip->saddr;
653         dst = ip->daddr;
654         oldtos = ip->tos;
655
656         /*
657          *      If we got interface from which packet came
658          *      we can use the address directly. Linux 2.1 now uses address
659          *      chains per device too, but unlike BSD we first check if the
660          *      incoming packet matches a device address and the routing
661          *      table before calling the firewall.
662          */
663
664         dprintf("Packet ");
665         switch(ip->protocol)
666         {
667                 case IPPROTO_TCP:
668                         dprintf("TCP ");
669                         if (!offset) {
670                                 src_port=ntohs(tcp->source);
671                                 dst_port=ntohs(tcp->dest);
672
673                                 /* Connection initilisation can only
674                                  * be made when the syn bit is set and
675                                  * neither of the ack or reset is
676                                  * set. */
677                                 if(tcp->syn && !(tcp->ack || tcp->rst))
678                                         tcpsyn=1;
679                         }
680                         break;
681                 case IPPROTO_UDP:
682                         dprintf("UDP ");
683                         if (!offset) {
684                                 src_port=ntohs(udp->source);
685                                 dst_port=ntohs(udp->dest);
686                         }
687                         break;
688                 case IPPROTO_ICMP:
689                         if (!offset) {
690                                 src_port=(__u16)icmp->type;
691                                 dst_port=(__u16)icmp->code;
692                         }
693                         dprintf("ICMP ");
694                         break;
695                 default:
696                         dprintf("p=%d ",ip->protocol);
697                         break;
698         }
699 #ifdef DEBUG_IP_FIREWALL
700         print_ip(ip->saddr);
701
702         if (offset)
703                 dprintf(":fragment (%i) ", ((int)offset)<<2);
704         else if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP
705                  || ip->protocol==IPPROTO_ICMP)
706                 dprintf(":%hu:%hu", src_port, dst_port);
707         dprintf("\n");
708 #endif
709
710         if (!testing) FWC_READ_LOCK(&ip_fw_lock);
711         else FWC_HAVE_LOCK(fwc_rlocks);
712
713         f = chain->chain;
714         do {
715                 count = 0;
716                 for (; f; f = f->next) {
717                         count++;
718                         if (ip_rule_match(f,rif,ip,
719                                           tcpsyn,src_port,dst_port,offset)) {
720                                 if (!testing
721                                     && !ip_fw_domatch(f, ip, rif, chain->label,
722                                                       skb, slot,
723                                                       src_port, dst_port,
724                                                       count, tcpsyn)) {
725                                         ret = FW_BLOCK;
726                                         goto out;
727                                 }
728                                 break;
729                         }
730                 }
731                 if (f) {
732                         if (f->branch) {
733                                 /* Do sanity check to see if we have
734                                  * already set prevchain and if so we
735                                  * must be in a loop */
736                                 if (f->branch->reent[slot].prevchain) {
737                                         if (!testing) {
738                                                 printk(KERN_ERR
739                                                        "IP firewall: "
740                                                        "Loop detected "
741                                                        "at `%s'.\n",
742                                                        f->branch->label);
743                                                 cleanup(chain, 1, slot);
744                                                 ret = FW_BLOCK;
745                                         } else {
746                                                 cleanup(chain, 0, slot);
747                                                 ret = FW_SKIP+1;
748                                         }
749                                 }
750                                 else {
751                                         f->branch->reent[slot].prevchain
752                                                 = chain;
753                                         f->branch->reent[slot].prevrule
754                                                 = f->next;
755                                         chain = f->branch;
756                                         f = chain->chain;
757                                 }
758                         }
759                         else if (f->simplebranch == FW_SKIP)
760                                 f = f->next;
761                         else if (f->simplebranch == FW_SKIP+1) {
762                                 /* Just like falling off the chain */
763                                 goto fall_off_chain;
764                         } else {
765                                 cleanup(chain, 0, slot);
766                                 ret = f->simplebranch;
767                         }
768                 } /* f == NULL */
769                 else {
770                 fall_off_chain:
771                         if (chain->reent[slot].prevchain) {
772                                 struct ip_chain *tmp = chain;
773                                 f = chain->reent[slot].prevrule;
774                                 chain = chain->reent[slot].prevchain;
775                                 tmp->reent[slot].prevchain = NULL;
776                         }
777                         else {
778                                 ret = chain->policy;
779                                 if (!testing) {
780                                         chain->reent[slot].counters.pcnt++;
781                                         chain->reent[slot].counters.bcnt
782                                                 += ntohs(ip->tot_len);
783                                 }
784                         }
785                 }
786         } while (ret == FW_SKIP+2);
787
788  out:
789         if (!testing) FWC_READ_UNLOCK(&ip_fw_lock);
790
791         /* Recalculate checksum if not going to reject, and TOS changed. */
792         if (ip->tos != oldtos
793             && ret != FW_REJECT && ret != FW_BLOCK
794             && !testing)
795                 ip_send_check(ip);
796
797         if (ret == FW_REDIRECT && redirport) {
798                 if ((*redirport = htons(f->ipfw.fw_redirpt)) == 0) {
799                         /* Wildcard redirection.
800                          * Note that redirport will become
801                          * 0xFFFF for non-TCP/UDP packets.
802                          */
803                         *redirport = htons(dst_port);
804                 }
805         }
806
807 #ifdef DEBUG_ALLOW_ALL
808         return (testing ? ret : FW_ACCEPT);
809 #else
810         return ret;
811 #endif
812 }
813
814 /* Must have write lock & interrupts off for any of these */
815
816 /* This function sets all the byte counters in a chain to zero.  The
817  * input is a pointer to the chain required for zeroing */
818 static int zero_fw_chain(struct ip_chain *chainptr)
819 {
820         struct ip_fwkernel *i;
821
822         FWC_HAVE_LOCK(fwc_wlocks);
823         for (i = chainptr->chain; i; i = i->next)
824                 memset(i->counters, 0, sizeof(struct ip_counters)*NUM_SLOTS);
825         return 0;
826 }
827
828 static int clear_fw_chain(struct ip_chain *chainptr)
829 {
830         struct ip_fwkernel *i= chainptr->chain;
831
832         FWC_HAVE_LOCK(fwc_wlocks);
833         chainptr->chain=NULL;
834
835         while (i) {
836                 struct ip_fwkernel *tmp = i->next;
837                 if (i->branch)
838                         i->branch->refcount--;
839                 kfree(i);
840                 i = tmp;
841         }
842         return 0;
843 }
844
845 static int replace_in_chain(struct ip_chain *chainptr,
846                             struct ip_fwkernel *frwl,
847                             __u32 position)
848 {
849         struct ip_fwkernel *f = chainptr->chain;
850
851         FWC_HAVE_LOCK(fwc_wlocks);
852
853         while (--position && f != NULL) f = f->next;
854         if (f == NULL)
855                 return EINVAL;
856
857         if (f->branch) f->branch->refcount--;
858         if (frwl->branch) frwl->branch->refcount++;
859
860         frwl->next = f->next;
861         memcpy(f,frwl,sizeof(struct ip_fwkernel));
862         kfree(frwl);
863         return 0;
864 }
865
866 static int append_to_chain(struct ip_chain *chainptr, struct ip_fwkernel *rule)
867 {
868         struct ip_fwkernel *i;
869
870         FWC_HAVE_LOCK(fwc_wlocks);
871         /* Special case if no rules already present */
872         if (chainptr->chain == NULL) {
873
874                 /* If pointer writes are atomic then turning off
875                  * interrupts is not necessary. */
876                 chainptr->chain = rule;
877                 if (rule->branch) rule->branch->refcount++;
878                 return 0;
879         }
880
881         /* Find the rule before the end of the chain */
882         for (i = chainptr->chain; i->next; i = i->next);
883         i->next = rule;
884         if (rule->branch) rule->branch->refcount++;
885         return 0;
886 }
887
888 /* This function inserts a rule at the position of position in the
889  * chain refenced by chainptr.  If position is 1 then this rule will
890  * become the new rule one. */
891 static int insert_in_chain(struct ip_chain *chainptr,
892                            struct ip_fwkernel *frwl,
893                            __u32 position)
894 {
895         struct ip_fwkernel *f = chainptr->chain;
896
897         FWC_HAVE_LOCK(fwc_wlocks);
898         /* special case if the position is number 1 */
899         if (position == 1) {
900                 frwl->next = chainptr->chain;
901                 if (frwl->branch) frwl->branch->refcount++;
902                 chainptr->chain = frwl;
903                 return 0;
904         }
905         position--;
906         while (--position && f != NULL) f = f->next;
907         if (f == NULL)
908                 return EINVAL;
909         if (frwl->branch) frwl->branch->refcount++;
910         frwl->next = f->next;
911
912         f->next = frwl;
913         return 0;
914 }
915
916 /* This function deletes the a rule from a given rulenum and chain.
917  * With rulenum = 1 is the first rule is deleted. */
918
919 static int del_num_from_chain(struct ip_chain *chainptr, __u32 rulenum)
920 {
921         struct ip_fwkernel *i=chainptr->chain,*tmp;
922
923         FWC_HAVE_LOCK(fwc_wlocks);
924
925         if (!chainptr->chain)
926                 return ENOENT;
927
928         /* Need a special case for the first rule */
929         if (rulenum == 1) {
930                 /* store temp to allow for freeing up of memory */
931                 tmp = chainptr->chain;
932                 if (chainptr->chain->branch) chainptr->chain->branch->refcount--;
933                 chainptr->chain = chainptr->chain->next;
934                 kfree(tmp); /* free memory that is now unused */
935         } else {
936                 rulenum--;
937                 while (--rulenum && i->next ) i = i->next;
938                 if (!i->next)
939                         return ENOENT;
940                 tmp = i->next;
941                 if (i->next->branch)
942                         i->next->branch->refcount--;
943                 i->next = i->next->next;
944                 kfree(tmp);
945         }
946         return 0;
947 }
948
949
950 /* This function deletes the a rule from a given rule and chain.
951  * The rule that is deleted is the first occursance of that rule. */
952 static int del_rule_from_chain(struct ip_chain *chainptr,
953                                struct ip_fwkernel *frwl)
954 {
955         struct ip_fwkernel *ltmp,*ftmp = chainptr->chain ;
956         int was_found;
957
958         FWC_HAVE_LOCK(fwc_wlocks);
959
960         /* Sure, we should compare marks, but since the `ipfwadm'
961          * script uses it for an unholy hack... well, life is easier
962          * this way.  We also mask it out of the flags word. --PR */
963         for (ltmp=NULL, was_found=0;
964              !was_found && ftmp != NULL;
965              ltmp = ftmp,ftmp = ftmp->next) {
966                 if (ftmp->ipfw.fw_src.s_addr!=frwl->ipfw.fw_src.s_addr
967                     || ftmp->ipfw.fw_dst.s_addr!=frwl->ipfw.fw_dst.s_addr
968                     || ftmp->ipfw.fw_smsk.s_addr!=frwl->ipfw.fw_smsk.s_addr
969                     || ftmp->ipfw.fw_dmsk.s_addr!=frwl->ipfw.fw_dmsk.s_addr
970 #if 0
971                     || ftmp->ipfw.fw_flg!=frwl->ipfw.fw_flg
972 #else
973                     || ((ftmp->ipfw.fw_flg & ~IP_FW_F_MARKABS)
974                         != (frwl->ipfw.fw_flg & ~IP_FW_F_MARKABS))
975 #endif
976                     || ftmp->ipfw.fw_invflg!=frwl->ipfw.fw_invflg
977                     || ftmp->ipfw.fw_proto!=frwl->ipfw.fw_proto
978 #if 0
979                     || ftmp->ipfw.fw_mark!=frwl->ipfw.fw_mark
980 #endif
981                     || ftmp->ipfw.fw_redirpt!=frwl->ipfw.fw_redirpt
982                     || ftmp->ipfw.fw_spts[0]!=frwl->ipfw.fw_spts[0]
983                     || ftmp->ipfw.fw_spts[1]!=frwl->ipfw.fw_spts[1]
984                     || ftmp->ipfw.fw_dpts[0]!=frwl->ipfw.fw_dpts[0]
985                     || ftmp->ipfw.fw_dpts[1]!=frwl->ipfw.fw_dpts[1]
986                     || ftmp->ipfw.fw_outputsize!=frwl->ipfw.fw_outputsize) {
987                         duprintf("del_rule_from_chain: mismatch:"
988                                  "src:%u/%u dst:%u/%u smsk:%u/%u dmsk:%u/%u "
989                                  "flg:%hX/%hX invflg:%hX/%hX proto:%u/%u "
990                                  "mark:%u/%u "
991                                  "ports:%hu-%hu/%hu-%hu %hu-%hu/%hu-%hu "
992                                  "outputsize:%hu-%hu\n",
993                                  ftmp->ipfw.fw_src.s_addr,
994                                  frwl->ipfw.fw_src.s_addr,
995                                  ftmp->ipfw.fw_dst.s_addr,
996                                  frwl->ipfw.fw_dst.s_addr,
997                                  ftmp->ipfw.fw_smsk.s_addr,
998                                  frwl->ipfw.fw_smsk.s_addr,
999                                  ftmp->ipfw.fw_dmsk.s_addr,
1000                                  frwl->ipfw.fw_dmsk.s_addr,
1001                                  ftmp->ipfw.fw_flg,
1002                                  frwl->ipfw.fw_flg,
1003                                  ftmp->ipfw.fw_invflg,
1004                                  frwl->ipfw.fw_invflg,
1005                                  ftmp->ipfw.fw_proto,
1006                                  frwl->ipfw.fw_proto,
1007                                  ftmp->ipfw.fw_mark,
1008                                  frwl->ipfw.fw_mark,
1009                                  ftmp->ipfw.fw_spts[0],
1010                                  frwl->ipfw.fw_spts[0],
1011                                  ftmp->ipfw.fw_spts[1],
1012                                  frwl->ipfw.fw_spts[1],
1013                                  ftmp->ipfw.fw_dpts[0],
1014                                  frwl->ipfw.fw_dpts[0],
1015                                  ftmp->ipfw.fw_dpts[1],
1016                                  frwl->ipfw.fw_dpts[1],
1017                                  ftmp->ipfw.fw_outputsize,
1018                                  frwl->ipfw.fw_outputsize);
1019                         continue;
1020                 }
1021
1022                 if (strncmp(ftmp->ipfw.fw_vianame,
1023                             frwl->ipfw.fw_vianame,
1024                             IFNAMSIZ)) {
1025                         duprintf("del_rule_from_chain: if mismatch: %s/%s\n",
1026                                  ftmp->ipfw.fw_vianame,
1027                                  frwl->ipfw.fw_vianame);
1028                         continue;
1029                 }
1030                 if (ftmp->branch != frwl->branch) {
1031                         duprintf("del_rule_from_chain: branch mismatch: "
1032                                  "%s/%s\n",
1033                                  ftmp->branch?ftmp->branch->label:"(null)",
1034                                  frwl->branch?frwl->branch->label:"(null)");
1035                         continue;
1036                 }
1037                 if (ftmp->branch == NULL
1038                     && ftmp->simplebranch != frwl->simplebranch) {
1039                         duprintf("del_rule_from_chain: simplebranch mismatch: "
1040                                  "%i/%i\n",
1041                                  ftmp->simplebranch, frwl->simplebranch);
1042                         continue;
1043                 }
1044                 was_found = 1;
1045                 if (ftmp->branch)
1046                         ftmp->branch->refcount--;
1047                 if (ltmp)
1048                         ltmp->next = ftmp->next;
1049                 else
1050                         chainptr->chain = ftmp->next;
1051                 kfree(ftmp);
1052                 break;
1053         }
1054
1055         if (was_found)
1056                 return 0;
1057         else {
1058                 duprintf("del_rule_from_chain: no matching rule found\n");
1059                 return EINVAL;
1060         }
1061 }
1062
1063 /* This function takes the label of a chain and deletes the first
1064  * chain with that name.  No special cases required for the built in
1065  * chains as they have their refcount initilised to 1 so that they are
1066  * never deleted.  */
1067 static int del_chain(ip_chainlabel label)
1068 {
1069         struct ip_chain *tmp,*tmp2;
1070
1071         FWC_HAVE_LOCK(fwc_wlocks);
1072         /* Corner case: return EBUSY not ENOENT for first elem ("input") */
1073         if (strcmp(label, ip_fw_chains->label) == 0)
1074                 return EBUSY;
1075
1076         for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next)
1077                 if(strcmp(tmp->next->label,label) == 0)
1078                         break;
1079
1080         tmp2 = tmp->next;
1081         if (!tmp2)
1082                 return ENOENT;
1083
1084         if (tmp2->refcount)
1085                 return EBUSY;
1086
1087         if (tmp2->chain)
1088                 return ENOTEMPTY;
1089
1090         tmp->next = tmp2->next;
1091         kfree(tmp2);
1092         return 0;
1093 }
1094
1095 /* This is a function to initilise a chain.  Built in rules start with
1096  * refcount = 1 so that they cannot be deleted.  User defined rules
1097  * start with refcount = 0 so they can be deleted. */
1098 static struct ip_chain *ip_init_chain(ip_chainlabel name,
1099                                       __u32 ref,
1100                                       int policy)
1101 {
1102         unsigned int i;
1103         struct ip_chain *label
1104                 = kmalloc(SIZEOF_STRUCT_IP_CHAIN, GFP_KERNEL);
1105         if (label == NULL)
1106                 panic("Can't kmalloc for firewall chains.\n");
1107         strcpy(label->label,name);
1108         label->next = NULL;
1109         label->chain = NULL;
1110         label->refcount = ref;
1111         label->policy = policy;
1112         for (i = 0; i < smp_num_cpus*2; i++) {
1113                 label->reent[i].counters.pcnt = label->reent[i].counters.bcnt
1114                         = 0;
1115                 label->reent[i].prevchain = NULL;
1116                 label->reent[i].prevrule = NULL;
1117         }
1118
1119         return label;
1120 }
1121
1122 /* This is a function for reating a new chain.  The chains is not
1123  * created if a chain of the same name already exists */
1124 static int create_chain(ip_chainlabel label)
1125 {
1126         struct ip_chain *tmp;
1127
1128         if (!check_label(label))
1129                 return EINVAL;
1130
1131         FWC_HAVE_LOCK(fwc_wlocks);
1132         for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next)
1133                 if (strcmp(tmp->label,label) == 0)
1134                         return EEXIST;
1135
1136         if (strcmp(tmp->label,label) == 0)
1137                 return EEXIST;
1138
1139         tmp->next = ip_init_chain(label, 0, FW_SKIP); /* refcount is
1140                                               * zero since this is a
1141                                               * user defined chain *
1142                                               * and therefore can be
1143                                               * deleted */
1144         return 0;
1145 }
1146
1147 /* This function simply changes the policy on one of the built in
1148  * chains.  checking must be done before this is call to ensure that
1149  * chainptr is pointing to one of the three possible chains */
1150 static int change_policy(struct ip_chain *chainptr, int policy)
1151 {
1152         FWC_HAVE_LOCK(fwc_wlocks);
1153         chainptr->policy = policy;
1154         return 0;
1155 }
1156
1157 /* This function takes an ip_fwuser and converts it to a ip_fwkernel.  It also
1158  * performs some checks in the structure. */
1159 static struct ip_fwkernel *convert_ipfw(struct ip_fwuser *fwuser, int *errno)
1160 {
1161         struct ip_fwkernel *fwkern;
1162
1163         if ( (fwuser->ipfw.fw_flg & ~IP_FW_F_MASK) != 0 ) {
1164                 duprintf("convert_ipfw: undefined flag bits set (flags=%x)\n",
1165                          fwuser->ipfw.fw_flg);
1166                 *errno = EINVAL;
1167                 return NULL;
1168         }
1169
1170 #ifdef DEBUG_IP_FIREWALL_USER
1171         /* These are sanity checks that don't really matter.
1172          * We can get rid of these once testing is complete.
1173          */
1174         if ((fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN)
1175             && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO)
1176                 || fwuser->ipfw.fw_proto != IPPROTO_TCP)) {
1177                 duprintf("convert_ipfw: TCP SYN flag set but proto != TCP!\n");
1178                 *errno = EINVAL;
1179                 return NULL;
1180         }
1181
1182         if (strcmp(fwuser->label, IP_FW_LABEL_REDIRECT) != 0
1183             && fwuser->ipfw.fw_redirpt != 0) {
1184                 duprintf("convert_ipfw: Target not REDIR but redirpt != 0!\n");
1185                 *errno = EINVAL;
1186                 return NULL;
1187         }
1188
1189         if ((!(fwuser->ipfw.fw_flg & IP_FW_F_FRAG)
1190              && (fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG))
1191             || (!(fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN)
1192                 && (fwuser->ipfw.fw_invflg & IP_FW_INV_SYN))) {
1193                 duprintf("convert_ipfw: Can't have INV flag if flag unset!\n");
1194                 *errno = EINVAL;
1195                 return NULL;
1196         }
1197
1198         if (((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCPT)
1199              && fwuser->ipfw.fw_spts[0] == 0
1200              && fwuser->ipfw.fw_spts[1] == 0xFFFF)
1201             || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTPT)
1202                 && fwuser->ipfw.fw_dpts[0] == 0
1203                 && fwuser->ipfw.fw_dpts[1] == 0xFFFF)
1204             || ((fwuser->ipfw.fw_invflg & IP_FW_INV_VIA)
1205                 && (fwuser->ipfw.fw_vianame)[0] == '\0')
1206             || ((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCIP)
1207                 && fwuser->ipfw.fw_smsk.s_addr == 0)
1208             || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTIP)
1209                 && fwuser->ipfw.fw_dmsk.s_addr == 0)) {
1210                 duprintf("convert_ipfw: INV flag makes rule unmatchable!\n");
1211                 *errno = EINVAL;
1212                 return NULL;
1213         }
1214
1215         if ((fwuser->ipfw.fw_flg & IP_FW_F_FRAG)
1216             && !(fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG)
1217             && (fwuser->ipfw.fw_spts[0] != 0
1218                 || fwuser->ipfw.fw_spts[1] != 0xFFFF
1219                 || fwuser->ipfw.fw_dpts[0] != 0
1220                 || fwuser->ipfw.fw_dpts[1] != 0xFFFF
1221                 || (fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN))) {
1222                 duprintf("convert_ipfw: Can't test ports or SYN with frag!\n");
1223                 *errno = EINVAL;
1224                 return NULL;
1225         }
1226 #endif
1227
1228         if ((fwuser->ipfw.fw_spts[0] != 0
1229              || fwuser->ipfw.fw_spts[1] != 0xFFFF
1230              || fwuser->ipfw.fw_dpts[0] != 0
1231              || fwuser->ipfw.fw_dpts[1] != 0xFFFF)
1232             && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO)
1233                 || (fwuser->ipfw.fw_proto != IPPROTO_TCP
1234                     && fwuser->ipfw.fw_proto != IPPROTO_UDP
1235                     && fwuser->ipfw.fw_proto != IPPROTO_ICMP))) {
1236                 duprintf("convert_ipfw: Can only test ports for TCP/UDP/ICMP!\n");
1237                 *errno = EINVAL;
1238                 return NULL;
1239         }
1240
1241         fwkern = kmalloc(SIZEOF_STRUCT_IP_FW_KERNEL, GFP_KERNEL);
1242         if (!fwkern) {
1243                 duprintf("convert_ipfw: kmalloc failed!\n");
1244                 *errno = ENOMEM;
1245                 return NULL;
1246         }
1247         memcpy(&fwkern->ipfw,&fwuser->ipfw,sizeof(struct ip_fw));
1248
1249         if (!find_special(fwuser->label, &fwkern->simplebranch)) {
1250                 fwkern->branch = find_label(fwuser->label);
1251                 if (!fwkern->branch) {
1252                         duprintf("convert_ipfw: chain doesn't exist `%s'.\n",
1253                                  fwuser->label);
1254                         kfree(fwkern);
1255                         *errno = ENOENT;
1256                         return NULL;
1257                 } else if (fwkern->branch == IP_FW_INPUT_CHAIN
1258                            || fwkern->branch == IP_FW_FORWARD_CHAIN
1259                            || fwkern->branch == IP_FW_OUTPUT_CHAIN) {
1260                         duprintf("convert_ipfw: Can't branch to builtin chain `%s'.\n",
1261                                  fwuser->label);
1262                         kfree(fwkern);
1263                         *errno = ENOENT;
1264                         return NULL;
1265                 }
1266         } else
1267                 fwkern->branch = NULL;
1268         memset(fwkern->counters, 0, sizeof(struct ip_counters)*NUM_SLOTS);
1269
1270         /* Handle empty vianame by making it a wildcard */
1271         if ((fwkern->ipfw.fw_vianame)[0] == '\0')
1272             fwkern->ipfw.fw_flg |= IP_FW_F_WILDIF;
1273
1274         fwkern->next = NULL;
1275         return fwkern;
1276 }
1277
1278 int ip_fw_ctl(int cmd, void *m, int len)
1279 {
1280         int ret;
1281         struct ip_chain *chain;
1282         unsigned long flags;
1283
1284         FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags);
1285
1286         switch (cmd) {
1287         case IP_FW_FLUSH:
1288                 if (len != sizeof(ip_chainlabel) || !check_label(m))
1289                         ret = EINVAL;
1290                 else if ((chain = find_label(m)) == NULL)
1291                         ret = ENOENT;
1292                 else ret = clear_fw_chain(chain);
1293                 break;
1294
1295         case IP_FW_ZERO:
1296                 if (len != sizeof(ip_chainlabel) || !check_label(m))
1297                         ret = EINVAL;
1298                 else if ((chain = find_label(m)) == NULL)
1299                         ret = ENOENT;
1300                 else ret = zero_fw_chain(chain);
1301                 break;
1302
1303         case IP_FW_CHECK: {
1304                 struct ip_fwtest *new = m;
1305                 struct iphdr *ip;
1306
1307                 /* Don't need write lock. */
1308                 FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags);
1309
1310                 if (len != sizeof(struct ip_fwtest) || !check_label(m))
1311                         return EINVAL;
1312
1313                 /* Need readlock to do find_label */
1314                 FWC_READ_LOCK(&ip_fw_lock);
1315
1316                 if ((chain = find_label(new->fwt_label)) == NULL)
1317                         ret = ENOENT;
1318                 else {
1319                         ip = &(new->fwt_packet.fwp_iph);
1320
1321                         if (ip->ihl != sizeof(struct iphdr) / sizeof(int)) {
1322                             duprintf("ip_fw_ctl: ip->ihl=%d, want %d\n",
1323                                      ip->ihl,
1324                                      sizeof(struct iphdr) / sizeof(int));
1325                             ret = EINVAL;
1326                         }
1327                         else {
1328                                 ret = ip_fw_check(ip, new->fwt_packet.fwp_vianame,
1329                                                   NULL, chain,
1330                                                   NULL, SLOT_NUMBER(), 1);
1331                                 switch (ret) {
1332                                 case FW_ACCEPT:
1333                                         ret = 0; break;
1334                                 case FW_REDIRECT:
1335                                         ret = ECONNABORTED; break;
1336                                 case FW_MASQUERADE:
1337                                         ret = ECONNRESET; break;
1338                                 case FW_REJECT:
1339                                         ret = ECONNREFUSED; break;
1340                                         /* Hack to help diag; these only get
1341                                            returned when testing. */
1342                                 case FW_SKIP+1:
1343                                         ret = ELOOP; break;
1344                                 case FW_SKIP:
1345                                         ret = ENFILE; break;
1346                                 default: /* FW_BLOCK */
1347                                         ret = ETIMEDOUT; break;
1348                                 }
1349                         }
1350                 }
1351                 FWC_READ_UNLOCK(&ip_fw_lock);
1352                 return ret;
1353         }
1354
1355         case IP_FW_MASQ_TIMEOUTS: {
1356                 ret = ip_fw_masq_timeouts(m, len);
1357         }
1358         break;
1359
1360         case IP_FW_REPLACE: {
1361                 struct ip_fwkernel *ip_fwkern;
1362                 struct ip_fwnew *new = m;
1363
1364                 if (len != sizeof(struct ip_fwnew)
1365                     || !check_label(new->fwn_label))
1366                         ret = EINVAL;
1367                 else if ((chain = find_label(new->fwn_label)) == NULL)
1368                         ret = ENOENT;
1369                 else if ((ip_fwkern = convert_ipfw(&new->fwn_rule, &ret))
1370                          != NULL)
1371                         ret = replace_in_chain(chain, ip_fwkern,
1372                                                new->fwn_rulenum);
1373         }
1374         break;
1375
1376         case IP_FW_APPEND: {
1377                 struct ip_fwchange *new = m;
1378                 struct ip_fwkernel *ip_fwkern;
1379
1380                 if (len != sizeof(struct ip_fwchange)
1381                     || !check_label(new->fwc_label))
1382                         ret = EINVAL;
1383                 else if ((chain = find_label(new->fwc_label)) == NULL)
1384                         ret = ENOENT;
1385                 else if ((ip_fwkern = convert_ipfw(&new->fwc_rule, &ret))
1386                          != NULL)
1387                         ret = append_to_chain(chain, ip_fwkern);
1388         }
1389         break;
1390
1391         case IP_FW_INSERT: {
1392                 struct ip_fwkernel *ip_fwkern;
1393                 struct ip_fwnew *new = m;
1394
1395                 if (len != sizeof(struct ip_fwnew)
1396                     || !check_label(new->fwn_label))
1397                         ret = EINVAL;
1398                 else if ((chain = find_label(new->fwn_label)) == NULL)
1399                         ret = ENOENT;
1400                 else if ((ip_fwkern = convert_ipfw(&new->fwn_rule, &ret))
1401                          != NULL)
1402                         ret = insert_in_chain(chain, ip_fwkern,
1403                                               new->fwn_rulenum);
1404         }
1405         break;
1406
1407         case IP_FW_DELETE: {
1408                 struct ip_fwchange *new = m;
1409                 struct ip_fwkernel *ip_fwkern;
1410
1411                 if (len != sizeof(struct ip_fwchange)
1412                     || !check_label(new->fwc_label))
1413                         ret = EINVAL;
1414                 else if ((chain = find_label(new->fwc_label)) == NULL)
1415                         ret = ENOENT;
1416                 else if ((ip_fwkern = convert_ipfw(&new->fwc_rule, &ret))
1417                          != NULL) {
1418                         ret = del_rule_from_chain(chain, ip_fwkern);
1419                         kfree(ip_fwkern);
1420                 }
1421         }
1422         break;
1423
1424         case IP_FW_DELETE_NUM: {
1425                 struct ip_fwdelnum *new = m;
1426
1427                 if (len != sizeof(struct ip_fwdelnum)
1428                     || !check_label(new->fwd_label))
1429                         ret = EINVAL;
1430                 else if ((chain = find_label(new->fwd_label)) == NULL)
1431                         ret = ENOENT;
1432                 else ret = del_num_from_chain(chain, new->fwd_rulenum);
1433         }
1434         break;
1435
1436         case IP_FW_CREATECHAIN: {
1437                 if (len != sizeof(ip_chainlabel)) {
1438                         duprintf("create_chain: bad size %i\n", len);
1439                         ret = EINVAL;
1440                 }
1441                 else ret = create_chain(m);
1442         }
1443         break;
1444
1445         case IP_FW_DELETECHAIN: {
1446                 if (len != sizeof(ip_chainlabel)) {
1447                         duprintf("delete_chain: bad size %i\n", len);
1448                         ret = EINVAL;
1449                 }
1450                 else ret = del_chain(m);
1451         }
1452         break;
1453
1454         case IP_FW_POLICY: {
1455                 struct ip_fwpolicy *new = m;
1456
1457                 if (len != sizeof(struct ip_fwpolicy)
1458                     || !check_label(new->fwp_label))
1459                         ret = EINVAL;
1460                 else if ((chain = find_label(new->fwp_label)) == NULL)
1461                         ret = ENOENT;
1462                 else if (chain != IP_FW_INPUT_CHAIN
1463                          && chain != IP_FW_FORWARD_CHAIN
1464                          && chain != IP_FW_OUTPUT_CHAIN) {
1465                         duprintf("change_policy: can't change policy on user"
1466                                  " defined chain.\n");
1467                         ret = EINVAL;
1468                 }
1469                 else {
1470                         int pol = FW_SKIP;
1471                         find_special(new->fwp_policy, &pol);
1472
1473                         switch(pol) {
1474                         case FW_MASQUERADE:
1475                                 if (chain != IP_FW_FORWARD_CHAIN) {
1476                                         ret = EINVAL;
1477                                         break;
1478                                 }
1479                                 /* Fall thru... */
1480                         case FW_BLOCK:
1481                         case FW_ACCEPT:
1482                         case FW_REJECT:
1483                                 ret = change_policy(chain, pol);
1484                                 break;
1485                         default:
1486                                 duprintf("change_policy: bad policy `%s'\n",
1487                                          new->fwp_policy);
1488                                 ret = EINVAL;
1489                         }
1490                 }
1491                 break;
1492         }
1493         default:
1494                 duprintf("ip_fw_ctl:  unknown request %d\n",cmd);
1495                 ret = ENOPROTOOPT;
1496         }
1497
1498         FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags);
1499         return ret;
1500 }
1501
1502 /* Returns bytes used - doesn't NUL terminate */
1503 static int dump_rule(char *buffer,
1504                      const char *chainlabel,
1505                      const struct ip_fwkernel *rule)
1506 {
1507         int len;
1508         unsigned int i;
1509         __u64 packets = 0, bytes = 0;
1510
1511         FWC_HAVE_LOCK(fwc_wlocks);
1512         for (i = 0; i < NUM_SLOTS; i++) {
1513                 packets += rule->counters[i].pcnt;
1514                 bytes += rule->counters[i].bcnt;
1515         }
1516
1517         len=sprintf(buffer,
1518                     "%9s "                      /* Chain name */
1519                     "%08X/%08X->%08X/%08X "     /* Source & Destination IPs */
1520                     "%.16s "                    /* Interface */
1521                     "%X %X "                    /* fw_flg and fw_invflg fields */
1522                     "%u "                       /* Protocol */
1523                     "%-9u %-9u %-9u %-9u "      /* Packet & byte counters */
1524                     "%u-%u %u-%u "              /* Source & Dest port ranges */
1525                     "A%02X X%02X "              /* TOS and and xor masks */
1526                     "%08X "                     /* Redirection port */
1527                     "%u "                       /* fw_mark field */
1528                     "%u "                       /* output size */
1529                     "%9s\n",                    /* Target */
1530                     chainlabel,
1531                     ntohl(rule->ipfw.fw_src.s_addr),
1532                     ntohl(rule->ipfw.fw_smsk.s_addr),
1533                     ntohl(rule->ipfw.fw_dst.s_addr),
1534                     ntohl(rule->ipfw.fw_dmsk.s_addr),
1535                     (rule->ipfw.fw_vianame)[0] ? rule->ipfw.fw_vianame : "-",
1536                     rule->ipfw.fw_flg,
1537                     rule->ipfw.fw_invflg,
1538                     rule->ipfw.fw_proto,
1539                     (__u32)(packets >> 32), (__u32)packets,
1540                     (__u32)(bytes >> 32), (__u32)bytes,
1541                     rule->ipfw.fw_spts[0], rule->ipfw.fw_spts[1],
1542                     rule->ipfw.fw_dpts[0], rule->ipfw.fw_dpts[1],
1543                     rule->ipfw.fw_tosand, rule->ipfw.fw_tosxor,
1544                     rule->ipfw.fw_redirpt,
1545                     rule->ipfw.fw_mark,
1546                     rule->ipfw.fw_outputsize,
1547                     branchname(rule->branch,rule->simplebranch));
1548
1549         duprintf("dump_rule: %i bytes done.\n", len);
1550         return len;
1551 }
1552
1553 /* File offset is actually in records, not bytes. */
1554 static int ip_chain_procinfo(char *buffer, char **start,
1555                              off_t offset, int length
1556 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29)
1557                              , int reset
1558 #endif
1559         )
1560 {
1561 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29)
1562         /* FIXME: No more `atomic' read and reset.  Wonderful 8-( --RR */
1563         int reset = 0;
1564 #endif
1565         struct ip_chain *i;
1566         struct ip_fwkernel *j = ip_fw_chains->chain;
1567         unsigned long flags;
1568         int len = 0;
1569         int last_len = 0;
1570         off_t upto = 0;
1571
1572         duprintf("Offset starts at %lu\n", offset);
1573         duprintf("ip_fw_chains is 0x%0lX\n", (unsigned long int)ip_fw_chains);
1574
1575         /* Need a write lock to lock out ``readers'' which update counters. */
1576         FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags);
1577
1578         for (i = ip_fw_chains; i; i = i->next) {
1579             for (j = i->chain; j; j = j->next) {
1580                 if (upto == offset) break;
1581                 duprintf("Skipping rule in chain `%s'\n",
1582                          i->label);
1583                 upto++;
1584             }
1585             if (upto == offset) break;
1586         }
1587
1588         /* Don't init j first time, or once i = NULL */
1589         for (; i; (void)((i = i->next) && (j = i->chain))) {
1590                 duprintf("Dumping chain `%s'\n", i->label);
1591                 for (; j; j = j->next, upto++, last_len = len)
1592                 {
1593                         len += dump_rule(buffer+len, i->label, j);
1594                         if (len > length) {
1595                                 duprintf("Dumped to %i (past %i).  "
1596                                          "Moving back to %i.\n",
1597                                          len, length, last_len);
1598                                 len = last_len;
1599                                 goto outside;
1600                         }
1601                         else if (reset)
1602                                 memset(j->counters, 0,
1603                                        sizeof(struct ip_counters)*NUM_SLOTS);
1604                 }
1605         }
1606 outside:
1607         FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags);
1608         buffer[len] = '\0';
1609
1610         duprintf("ip_chain_procinfo: Length = %i (of %i).  Offset = %li.\n",
1611                  len, length, upto);
1612         /* `start' hack - see fs/proc/generic.c line ~165 */
1613         *start=(char *)((unsigned int)upto-offset);
1614         return len;
1615 }
1616
1617 static int ip_chain_name_procinfo(char *buffer, char **start,
1618                                   off_t offset, int length)
1619 {
1620         struct ip_chain *i;
1621         int len = 0,last_len = 0;
1622         off_t pos = 0,begin = 0;
1623         unsigned long flags;
1624
1625         /* Need a write lock to lock out ``readers'' which update counters. */
1626         FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags);
1627
1628         for (i = ip_fw_chains; i; i = i->next)
1629         {
1630                 unsigned int j;
1631                 __u32 packetsHi = 0, packetsLo = 0, bytesHi = 0, bytesLo = 0;
1632
1633                 for (j = 0; j < NUM_SLOTS; j++) {
1634                         packetsLo += i->reent[j].counters.pcnt & 0xFFFFFFFF;
1635                         packetsHi += ((i->reent[j].counters.pcnt >> 32)
1636                                       & 0xFFFFFFFF);
1637                         bytesLo += i->reent[j].counters.bcnt & 0xFFFFFFFF;
1638                         bytesHi += ((i->reent[j].counters.bcnt >> 32)
1639                                     & 0xFFFFFFFF);
1640                 }
1641
1642                 /* print the label and the policy */
1643                 len+=sprintf(buffer+len,"%s %s %i %u %u %u %u\n",
1644                              i->label,branchname(NULL, i->policy),i->refcount,
1645                              packetsHi, packetsLo, bytesHi, bytesLo);
1646                 pos=begin+len;
1647                 if(pos<offset) {
1648                         len=0;
1649                         begin=pos;
1650                 }
1651                 else if(pos>offset+length) {
1652                         len = last_len;
1653                         break;
1654                 }
1655
1656                 last_len = len;
1657         }
1658         FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags);
1659
1660         *start = buffer+(offset-begin);
1661         len-=(offset-begin);
1662         if(len>length)
1663                 len=length;
1664         return len;
1665 }
1666
1667 /*
1668  *      Interface to the generic firewall chains.
1669  */
1670 int ipfw_input_check(struct firewall_ops *this, int pf,
1671                      struct net_device *dev, void *phdr, void *arg,
1672                      struct sk_buff **pskb)
1673 {
1674         return ip_fw_check(phdr, dev->name,
1675                            arg, IP_FW_INPUT_CHAIN, *pskb, SLOT_NUMBER(), 0);
1676 }
1677
1678 int ipfw_output_check(struct firewall_ops *this, int pf,
1679                       struct net_device *dev, void *phdr, void *arg,
1680                       struct sk_buff **pskb)
1681 {
1682         /* Locally generated bogus packets by root. <SIGH>. */
1683         if (((struct iphdr *)phdr)->ihl * 4 < sizeof(struct iphdr)
1684             || (*pskb)->len < sizeof(struct iphdr))
1685                 return FW_ACCEPT;
1686         return ip_fw_check(phdr, dev->name,
1687                            arg, IP_FW_OUTPUT_CHAIN, *pskb, SLOT_NUMBER(), 0);
1688 }
1689
1690 int ipfw_forward_check(struct firewall_ops *this, int pf,
1691                        struct net_device *dev, void *phdr, void *arg,
1692                        struct sk_buff **pskb)
1693 {
1694         return ip_fw_check(phdr, dev->name,
1695                            arg, IP_FW_FORWARD_CHAIN, *pskb, SLOT_NUMBER(), 0);
1696 }
1697
1698 struct firewall_ops ipfw_ops=
1699 {
1700         NULL,
1701         ipfw_forward_check,
1702         ipfw_input_check,
1703         ipfw_output_check,
1704         NULL,
1705         NULL
1706 };
1707
1708 int ipfw_init_or_cleanup(int init)
1709 {
1710         struct proc_dir_entry *proc;
1711         int ret = 0;
1712         unsigned long flags;
1713
1714         if (!init) goto cleanup;
1715
1716 #ifdef DEBUG_IP_FIREWALL_LOCKING
1717         fwc_wlocks = fwc_rlocks = 0;
1718 #endif
1719
1720 #if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
1721         ipfwsk = netlink_kernel_create(NETLINK_FIREWALL, NULL);
1722         if (ipfwsk == NULL)
1723                 goto cleanup_nothing;
1724 #endif
1725
1726         ret = register_firewall(PF_INET, &ipfw_ops);
1727         if (ret < 0)
1728                 goto cleanup_netlink;
1729
1730         proc = proc_net_create(IP_FW_PROC_CHAINS, S_IFREG | S_IRUSR | S_IWUSR,
1731                                ip_chain_procinfo);
1732         if (proc) proc->owner = THIS_MODULE;
1733         proc = proc_net_create(IP_FW_PROC_CHAIN_NAMES,
1734                                S_IFREG | S_IRUSR | S_IWUSR,
1735                                ip_chain_name_procinfo);
1736         if (proc) proc->owner = THIS_MODULE;
1737
1738         IP_FW_INPUT_CHAIN = ip_init_chain(IP_FW_LABEL_INPUT, 1, FW_ACCEPT);
1739         IP_FW_FORWARD_CHAIN = ip_init_chain(IP_FW_LABEL_FORWARD, 1, FW_ACCEPT);
1740         IP_FW_OUTPUT_CHAIN = ip_init_chain(IP_FW_LABEL_OUTPUT, 1, FW_ACCEPT);
1741
1742         return ret;
1743
1744  cleanup:
1745         unregister_firewall(PF_INET, &ipfw_ops);
1746
1747         FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags);
1748         while (ip_fw_chains) {
1749                 struct ip_chain *next = ip_fw_chains->next;
1750
1751                 clear_fw_chain(ip_fw_chains);
1752                 kfree(ip_fw_chains);
1753                 ip_fw_chains = next;
1754         }
1755         FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags);
1756
1757         proc_net_remove(IP_FW_PROC_CHAINS);
1758         proc_net_remove(IP_FW_PROC_CHAIN_NAMES);
1759
1760  cleanup_netlink:
1761 #if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
1762         sock_release(ipfwsk->socket);
1763
1764  cleanup_nothing:
1765 #endif
1766         return ret;
1767 }