| /* libipt_TCPLAG.c -- module for iptables to interface with TCPLAG target |
| * Copyright (C) 2002 Telford Tendys <telford@triode.net.au> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| /* |
| * Shared library add-on to iptables for TCPLAG target control |
| * |
| * This allows installation and removal of the TCPLAG target |
| * Note that there is a lot more commentary in this file than |
| * the average libipt target (i.e. more than none) but these |
| * are just my deductions based on examination of the source |
| * and |
| */ |
| #include <stdio.h> |
| #include <netdb.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <syslog.h> |
| #include <getopt.h> |
| #include <iptables.h> |
| #include <linux/netfilter_ipv4/ip_tables.h> |
| #include <linux/netfilter_ipv4/ipt_TCPLAG.h> |
| |
| /* |
| * This merely dumps out text for the user |
| * (saves keeping the manpage up to date) |
| */ |
| static void help( void ) |
| { |
| printf( "TCPLAG options:\n" |
| " --log-level=n Set the syslog level to n (integer 0 to 7)\n\n" |
| " --log-prefix=xx Prefix log messages with xx\n" ); |
| } |
| |
| /* |
| * See "man getopt_long" for an explanation of this structure |
| * |
| * If one of our options DOES happen to come up then we get |
| * a callback into parse(), our vals must not overlap with any |
| * normal iptables short options (I think) because there is only |
| * one actual options handler and it can't tell whose options it |
| * is really looking at unless they are all distinct. |
| * |
| * These are exactly the same as the LOG target options |
| * and have the same purpose. |
| */ |
| static const struct option opts[] = |
| { |
| { "log-level", 1, 0, '!' }, |
| { "log-prefix", 1, 0, '#' }, |
| { 0 } |
| }; |
| |
| /* |
| * This gives us a chance to install some initial values in |
| * our own private data structure (which is at t->data). |
| * Probably we could fiddle with t->tflags too but there is |
| * no great advantage in doing so. |
| * |
| * TODO: Find documentation for the above flags which |
| * can be ored into nfcache... |
| * |
| * NFC_IP6_DST_PT |
| * NFC_IP6_PROTO_UNKNOWN |
| * NFC_IP6_SRC_PT |
| * NFC_IP6_TCPFLAGS |
| * NFC_IP_DST_PT |
| * NFC_IP_SRC_PT |
| * NFC_IP_TOS |
| * NFC_UNKNOWN -- This one seems safest |
| */ |
| static void init( struct ipt_entry_target *t, unsigned int *nfcache ) |
| { |
| struct ipt_tcplag *el = (struct ipt_tcplag *)t->data; |
| memset( el, 0, sizeof( struct ipt_tcplag )); |
| el->level = 4; /* Default to warning level */ |
| strcpy( el->prefix, "TCPLAG:" ); /* Give a reasonable default prefix */ |
| *nfcache |= NFC_UNKNOWN; |
| } |
| |
| /* |
| * It doesn't take much thought to see how little thought has gone into |
| * this particular API. However, to add to that I'd just like to say that |
| * it can be made to work and small miracles are still miracles. |
| * |
| * The input parameters are as follows: |
| * |
| * c -- the 'val' from opts[] above, could possibly be something |
| * we cannot recognise in which case return(0). |
| * If we do recognise it then return(1). |
| * |
| * argv -- in case we want to take parameters from the command line, |
| * not sure how to safely ensure that the parameter that |
| * we want to take will really exist, presumably getopt_long() |
| * will have already checked such things (what about optional |
| * parameters huh?). |
| * |
| * invert -- if the option parameter had '!' in front of it, usually this |
| * would inversion of the matching sense but I don't think it |
| * is useful in the case of targets. |
| * |
| * flags -- always (*target)->tflags for those who feel it is better |
| * to access this field indirectly <shrug> starts of |
| * zero for a fresh target, gets fed into final_check(). |
| * |
| * entry -- apparently useless |
| * |
| * target -- the record that holds data about this target, |
| * most importantly, our private data is (*target)->data |
| * (this has already been malloced for us). |
| */ |
| static int parse( int c, char **argv, int invert, unsigned int *flags, |
| const struct ipt_entry *entry, struct ipt_entry_target **target ) |
| { |
| struct ipt_tcplag *el = (struct ipt_tcplag *)( *target )->data; |
| /* |
| * Yeah, we could complain about options being issued twice but |
| * is it really worth the trouble? Will it make the world a better place? |
| */ |
| switch( c ) |
| { |
| /* |
| * I really can't be bothered with the syslog naming convention, |
| * it isn't terribly useful anyhow. |
| */ |
| case '!': |
| el->level = strtol( optarg, 0, 10 ); |
| return( 1 ); |
| /* |
| * 15 chars should be plenty |
| */ |
| case '#': |
| strncpy( el->prefix, optarg, 15 ); |
| el->prefix[ 14 ] = 0; /* Force termination */ |
| return( 1 ); |
| } |
| return( 0 ); |
| } |
| |
| /* |
| * This gets given the (*target)->tflags value from |
| * the parse() above and it gets called after all the |
| * parsing of options is completed. Thus if one option |
| * requires another option you can test the flags and |
| * decide whether everything is in order. |
| * |
| * If there is a problem then do something like: |
| * exit_error( PARAMETER_PROBLEM, "foobar parameters detected in TCPLAG target"); |
| * |
| * In this case, no errors are possible |
| */ |
| static void final_check( unsigned int flags ) { } |
| /* |
| * This print is for the purpose of user-readable display |
| * such as what "iptables -L" would give. The notes in |
| * iptables.h say that target could possibly be a null pointer |
| * but coding of the various libipt_XX.c modules suggests |
| * that it is safe to presume target is correctly initialised. |
| */ |
| static void print(const struct ipt_ip *ip, const struct ipt_entry_target *target, int numeric) |
| { |
| const struct ipt_tcplag *el = (const struct ipt_tcplag *)target->data; |
| printf("TCPLAG <%d>", el->level ); |
| if( el->prefix[ 0 ]) |
| { |
| printf( "%s", el->prefix ); |
| } |
| } |
| |
| /* |
| * As above but command-line style printout |
| * (machine-readable for restoring table) |
| */ |
| static void save( const struct ipt_ip *ip, const struct ipt_entry_target *target ) |
| { |
| const struct ipt_tcplag *el = (const struct ipt_tcplag *)target->data; |
| printf("TCPLAG --log-level=%d", el->level ); |
| if( el->prefix[ 0 ]) |
| { |
| /* |
| * FIXME: Should have smarter quoting |
| */ |
| printf( " --log-prefix='%s'", el->prefix ); |
| } |
| } |
| |
| /* |
| * The version must match the iptables version exactly |
| * which is a big pain, could use `iptables -V` in makefile |
| * but we can't guarantee compatibility with all iptables |
| * so we are stuck with only supporting one particular version. |
| */ |
| static struct iptables_target targ = |
| { |
| next: 0, |
| name: "TCPLAG", |
| version: "1.2.3", |
| size: IPT_ALIGN( sizeof( struct ipt_tcplag )), |
| userspacesize: IPT_ALIGN( sizeof( struct ipt_tcplag )), |
| help: &help, |
| init: &init, |
| parse: &parse, |
| final_check: &final_check, |
| print: &print, |
| save: &save, |
| extra_opts: opts |
| }; |
| |
| /* |
| * Always nervous trusting _init() but oh well that is the standard |
| * so have to go ahead and use it. This registers your target into |
| * the list of available targets so that your options become available. |
| */ |
| void _init( void ) { register_target( &targ ); } |