iptables-1.2.9-2.3.1.src.rpm
[iptables.git] / extensions / libipt_TCPLAG.c
1 /* libipt_TCPLAG.c -- module for iptables to interface with TCPLAG target
2  * Copyright (C) 2002 Telford Tendys <telford@triode.net.au>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 /*
20  * Shared library add-on to iptables for TCPLAG target control
21  *
22  * This allows installation and removal of the TCPLAG target
23  * Note that there is a lot more commentary in this file than
24  * the average libipt target (i.e. more than none) but these
25  * are just my deductions based on examination of the source
26  * and 
27  */
28 #include <stdio.h>
29 #include <netdb.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <syslog.h>
33 #include <getopt.h>
34 #include <iptables.h>
35 #include <linux/netfilter_ipv4/ip_tables.h>
36 #include <linux/netfilter_ipv4/ipt_TCPLAG.h>
37
38 /*
39  * This merely dumps out text for the user
40  * (saves keeping the manpage up to date)
41  */
42 static void help( void )
43 {
44         printf( "TCPLAG options:\n"
45                         " --log-level=n    Set the syslog level to n (integer 0 to 7)\n\n"
46                         " --log-prefix=xx  Prefix log messages with xx\n" );
47 }
48
49 /*
50  * See "man getopt_long" for an explanation of this structure
51  *
52  * If one of our options DOES happen to come up then we get
53  * a callback into parse(), our vals must not overlap with any
54  * normal iptables short options (I think) because there is only
55  * one actual options handler and it can't tell whose options it
56  * is really looking at unless they are all distinct.
57  *
58  * These are exactly the same as the LOG target options
59  * and have the same purpose.
60  */
61 static const struct option opts[] =
62 {
63         { "log-level",     1, 0, '!' },
64         { "log-prefix",    1, 0, '#' },
65         { 0 }
66 };
67
68 /*
69  * This gives us a chance to install some initial values in
70  * our own private data structure (which is at t->data).
71  * Probably we could fiddle with t->tflags too but there is
72  * no great advantage in doing so.
73  * 
74  * TODO: Find documentation for the above flags which
75  *       can be ored into nfcache...
76  *
77  * NFC_IP6_DST_PT
78  * NFC_IP6_PROTO_UNKNOWN
79  * NFC_IP6_SRC_PT
80  * NFC_IP6_TCPFLAGS
81  * NFC_IP_DST_PT
82  * NFC_IP_SRC_PT
83  * NFC_IP_TOS
84  * NFC_UNKNOWN             -- This one seems safest
85  */
86 static void init( struct ipt_entry_target *t, unsigned int *nfcache )
87 {
88         struct ipt_tcplag *el = (struct ipt_tcplag *)t->data;
89         memset( el, 0, sizeof( struct ipt_tcplag ));
90         el->level = 4; /* Default to warning level */
91         strcpy( el->prefix, "TCPLAG:" ); /* Give a reasonable default prefix */
92         *nfcache |= NFC_UNKNOWN;
93 }
94
95 /*
96  * It doesn't take much thought to see how little thought has gone into
97  * this particular API. However, to add to that I'd just like to say that
98  * it can be made to work and small miracles are still miracles.
99  *
100  * The input parameters are as follows:
101  * 
102  *  c      --  the 'val' from opts[] above, could possibly be something
103  *             we cannot recognise in which case return(0).
104  *             If we do recognise it then return(1).
105  *
106  *  argv   --  in case we want to take parameters from the command line,
107  *             not sure how to safely ensure that the parameter that
108  *             we want to take will really exist, presumably getopt_long()
109  *             will have already checked such things (what about optional
110  *             parameters huh?).
111  *
112  *  invert --  if the option parameter had '!' in front of it, usually this
113  *             would inversion of the matching sense but I don't think it
114  *             is useful in the case of targets.
115  *
116  *  flags  --  always (*target)->tflags for those who feel it is better
117  *             to access this field indirectly <shrug> starts of
118  *             zero for a fresh target, gets fed into final_check().
119  *
120  *  entry  --  apparently useless
121  *
122  *  target --  the record that holds data about this target,
123  *             most importantly, our private data is (*target)->data
124  *             (this has already been malloced for us).
125  */
126 static int parse( int c, char **argv, int invert, unsigned int *flags,
127                                   const struct ipt_entry *entry, struct ipt_entry_target **target )
128 {
129         struct ipt_tcplag *el = (struct ipt_tcplag *)( *target )->data;
130 /*
131  * Yeah, we could complain about options being issued twice but
132  * is it really worth the trouble? Will it make the world a better place?
133  */
134         switch( c )
135         {
136 /*
137  * I really can't be bothered with the syslog naming convention,
138  * it isn't terribly useful anyhow.
139  */
140                 case '!':
141                         el->level = strtol( optarg, 0, 10 );
142                         return( 1 );
143 /*
144  * 15 chars should be plenty
145  */
146                 case '#':
147                         strncpy( el->prefix, optarg, 15 );
148                         el->prefix[ 14 ] = 0; /* Force termination */
149                         return( 1 );
150         }
151         return( 0 );
152 }
153
154 /*
155  * This gets given the (*target)->tflags value from
156  * the parse() above and it gets called after all the
157  * parsing of options is completed. Thus if one option
158  * requires another option you can test the flags and
159  * decide whether everything is in order.
160  *
161  * If there is a problem then do something like:
162  *              exit_error( PARAMETER_PROBLEM, "foobar parameters detected in TCPLAG target");
163  *
164  * In this case, no errors are possible
165  */
166 static void final_check( unsigned int flags ) { }
167 /*
168  * This print is for the purpose of user-readable display
169  * such as what "iptables -L" would give. The notes in
170  * iptables.h say that target could possibly be a null pointer
171  * but coding of the various libipt_XX.c modules suggests
172  * that it is safe to presume target is correctly initialised.
173  */
174 static void print(const struct ipt_ip *ip, const struct ipt_entry_target *target, int numeric)
175 {
176         const struct ipt_tcplag *el = (const struct ipt_tcplag *)target->data;
177         printf("TCPLAG <%d>", el->level );
178         if( el->prefix[ 0 ])
179         {
180                 printf( "%s", el->prefix );
181         }
182 }
183
184 /*
185  * As above but command-line style printout
186  * (machine-readable for restoring table)
187  */
188 static void save( const struct ipt_ip *ip, const struct ipt_entry_target *target )
189 {
190         const struct ipt_tcplag *el = (const struct ipt_tcplag *)target->data;
191         printf("TCPLAG --log-level=%d", el->level );
192         if( el->prefix[ 0 ])
193         {
194 /*
195  * FIXME: Should have smarter quoting
196  */
197                 printf( " --log-prefix='%s'", el->prefix );
198         }
199 }
200
201 /*
202  * The version must match the iptables version exactly
203  * which is a big pain, could use `iptables -V` in makefile
204  * but we can't guarantee compatibility with all iptables
205  * so we are stuck with only supporting one particular version.
206  */
207 static struct iptables_target targ =
208 {
209 next:             0,
210 name:             "TCPLAG",
211 version:          "1.2.3",
212 size:             IPT_ALIGN( sizeof( struct ipt_tcplag )),
213 userspacesize:    IPT_ALIGN( sizeof( struct ipt_tcplag )),
214 help:             &help,
215 init:             &init,
216 parse:            &parse,
217 final_check:      &final_check,
218 print:            &print,
219 save:             &save,
220 extra_opts:       opts
221 };
222
223 /*
224  * Always nervous trusting _init() but oh well that is the standard
225  * so have to go ahead and use it. This registers your target into
226  * the list of available targets so that your options become available.
227  */
228 void _init( void ) { register_target( &targ ); }