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 */ 42static 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 */ 61static 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 */ 74static void init( struct ipt_entry_target *t, unsigned int *nfcache ) 75{ 76 struct ipt_tcplag *el = (struct ipt_tcplag *)t->data; 77 memset( el, 0, sizeof( struct ipt_tcplag )); 78 el->level = 4; /* Default to warning level */ 79 strcpy( el->prefix, "TCPLAG:" ); /* Give a reasonable default prefix */ 80} 81 82/* 83 * It doesn't take much thought to see how little thought has gone into 84 * this particular API. However, to add to that I'd just like to say that 85 * it can be made to work and small miracles are still miracles. 86 * 87 * The input parameters are as follows: 88 * 89 * c -- the 'val' from opts[] above, could possibly be something 90 * we cannot recognise in which case return(0). 91 * If we do recognise it then return(1). 92 * 93 * argv -- in case we want to take parameters from the command line, 94 * not sure how to safely ensure that the parameter that 95 * we want to take will really exist, presumably getopt_long() 96 * will have already checked such things (what about optional 97 * parameters huh?). 98 * 99 * invert -- if the option parameter had '!' in front of it, usually this 100 * would inversion of the matching sense but I don't think it 101 * is useful in the case of targets. 102 * 103 * flags -- always (*target)->tflags for those who feel it is better 104 * to access this field indirectly <shrug> starts of 105 * zero for a fresh target, gets fed into final_check(). 106 * 107 * entry -- apparently useless 108 * 109 * target -- the record that holds data about this target, 110 * most importantly, our private data is (*target)->data 111 * (this has already been malloced for us). 112 */ 113static int parse( int c, char **argv, int invert, unsigned int *flags, 114 const struct ipt_entry *entry, struct ipt_entry_target **target ) 115{ 116 struct ipt_tcplag *el = (struct ipt_tcplag *)( *target )->data; 117/* 118 * Yeah, we could complain about options being issued twice but 119 * is it really worth the trouble? Will it make the world a better place? 120 */ 121 switch( c ) 122 { 123/* 124 * I really can't be bothered with the syslog naming convention, 125 * it isn't terribly useful anyhow. 126 */ 127 case '!': 128 el->level = strtol( optarg, 0, 10 ); 129 return( 1 ); 130/* 131 * 15 chars should be plenty 132 */ 133 case '#': 134 strncpy( el->prefix, optarg, 15 ); 135 el->prefix[ 14 ] = 0; /* Force termination */ 136 return( 1 ); 137 } 138 return( 0 ); 139} 140 141/* 142 * This gets given the (*target)->tflags value from 143 * the parse() above and it gets called after all the 144 * parsing of options is completed. Thus if one option 145 * requires another option you can test the flags and 146 * decide whether everything is in order. 147 * 148 * If there is a problem then do something like: 149 * exit_error( PARAMETER_PROBLEM, "foobar parameters detected in TCPLAG target"); 150 * 151 * In this case, no errors are possible 152 */ 153static void final_check( unsigned int flags ) { } 154/* 155 * This print is for the purpose of user-readable display 156 * such as what "iptables -L" would give. The notes in 157 * iptables.h say that target could possibly be a null pointer 158 * but coding of the various libipt_XX.c modules suggests 159 * that it is safe to presume target is correctly initialised. 160 */ 161static void print(const struct ipt_ip *ip, const struct ipt_entry_target *target, int numeric) 162{ 163 const struct ipt_tcplag *el = (const struct ipt_tcplag *)target->data; 164 printf("TCPLAG <%d>", el->level ); 165 if( el->prefix[ 0 ]) 166 { 167 printf( "%s", el->prefix ); 168 } 169} 170 171/* 172 * As above but command-line style printout 173 * (machine-readable for restoring table) 174 */ 175static void save( const struct ipt_ip *ip, const struct ipt_entry_target *target ) 176{ 177 const struct ipt_tcplag *el = (const struct ipt_tcplag *)target->data; 178 printf("TCPLAG --log-level=%d", el->level ); 179 if( el->prefix[ 0 ]) 180 { 181/* 182 * FIXME: Should have smarter quoting 183 */ 184 printf( " --log-prefix='%s'", el->prefix ); 185 } 186} 187 188/* 189 * The version must match the iptables version exactly 190 * which is a big pain, could use `iptables -V` in makefile 191 * but we can't guarantee compatibility with all iptables 192 * so we are stuck with only supporting one particular version. 193 */ 194static struct iptables_target targ = 195{ 196next: 0, 197name: "TCPLAG", 198version: IPTABLES_VERSION, 199size: IPT_ALIGN( sizeof( struct ipt_tcplag )), 200userspacesize: IPT_ALIGN( sizeof( struct ipt_tcplag )), 201help: &help, 202init: &init, 203parse: &parse, 204final_check: &final_check, 205print: &print, 206save: &save, 207extra_opts: opts 208}; 209 210/* 211 * Always nervous trusting _init() but oh well that is the standard 212 * so have to go ahead and use it. This registers your target into 213 * the list of available targets so that your options become available. 214 */ 215void _init( void ) { register_target( &targ ); } 216