Home | History | Annotate | Download | only in extensions
      1 /* Shared library add-on to iptables for DSCP
      2  *
      3  * (C) 2002 by Harald Welte <laforge (at) gnumonks.org>
      4  *
      5  * This program is distributed under the terms of GNU GPL v2, 1991
      6  *
      7  * libipt_dscp.c borrowed heavily from libipt_tos.c
      8  *
      9  * --class support added by Iain Barnes
     10  *
     11  * For a list of DSCP codepoints see
     12  * http://www.iana.org/assignments/dscp-registry
     13  *
     14  */
     15 #include <stdio.h>
     16 #include <string.h>
     17 #include <stdlib.h>
     18 #include <getopt.h>
     19 
     20 #include <iptables.h>
     21 #include <linux/netfilter_ipv4/ip_tables.h>
     22 #include <linux/netfilter_ipv4/ipt_2dscp.h>
     23 
     24 /* This is evil, but it's my code - HW*/
     25 #include "libipt_dscp_helper.c"
     26 
     27 static void help(void)
     28 {
     29 	printf(
     30 "DSCP match v%s options\n"
     31 "[!] --dscp value		Match DSCP codepoint with numerical value\n"
     32 "  		                This value can be in decimal (ex: 32)\n"
     33 "               		or in hex (ex: 0x20)\n"
     34 "[!] --dscp-class name		Match the DiffServ class. This value may\n"
     35 "				be any of the BE,EF, AFxx or CSx classes\n"
     36 "\n"
     37 "				These two options are mutually exclusive !\n"
     38 				, IPTABLES_VERSION
     39 );
     40 }
     41 
     42 static struct option opts[] = {
     43 	{ "dscp", 1, 0, 'F' },
     44 	{ "dscp-class", 1, 0, 'G' },
     45 	{ 0 }
     46 };
     47 
     48 static void
     49 parse_dscp(const char *s, struct ipt_dscp_info *dinfo)
     50 {
     51 	unsigned int dscp;
     52 
     53 	if (string_to_number(s, 0, 255, &dscp) == -1)
     54 		exit_error(PARAMETER_PROBLEM,
     55 			   "Invalid dscp `%s'\n", s);
     56 
     57 	if (dscp > IPT_DSCP_MAX)
     58 		exit_error(PARAMETER_PROBLEM,
     59 			   "DSCP `%d` out of range\n", dscp);
     60 
     61     	dinfo->dscp = (u_int8_t )dscp;
     62     	return;
     63 }
     64 
     65 
     66 static void
     67 parse_class(const char *s, struct ipt_dscp_info *dinfo)
     68 {
     69 	unsigned int dscp = class_to_dscp(s);
     70 
     71 	/* Assign the value */
     72 	dinfo->dscp = (u_int8_t)dscp;
     73 }
     74 
     75 
     76 static int
     77 parse(int c, char **argv, int invert, unsigned int *flags,
     78       const struct ipt_entry *entry,
     79       unsigned int *nfcache,
     80       struct ipt_entry_match **match)
     81 {
     82 	struct ipt_dscp_info *dinfo
     83 		= (struct ipt_dscp_info *)(*match)->data;
     84 
     85 	switch (c) {
     86 	case 'F':
     87 		if (*flags)
     88 			exit_error(PARAMETER_PROBLEM,
     89 			           "DSCP match: Only use --dscp ONCE!");
     90 		check_inverse(optarg, &invert, &optind, 0);
     91 		parse_dscp(argv[optind-1], dinfo);
     92 		if (invert)
     93 			dinfo->invert = 1;
     94 		*flags = 1;
     95 		break;
     96 
     97 	case 'G':
     98 		if (*flags)
     99 			exit_error(PARAMETER_PROBLEM,
    100 					"DSCP match: Only use --dscp-class ONCE!");
    101 		check_inverse(optarg, &invert, &optind, 0);
    102 		parse_class(argv[optind - 1], dinfo);
    103 		if (invert)
    104 			dinfo->invert = 1;
    105 		*flags = 1;
    106 		break;
    107 
    108 	default:
    109 		return 0;
    110 	}
    111 
    112 	return 1;
    113 }
    114 
    115 static void
    116 final_check(unsigned int flags)
    117 {
    118 	if (!flags)
    119 		exit_error(PARAMETER_PROBLEM,
    120 		           "DSCP match: Parameter --dscp is required");
    121 }
    122 
    123 static void
    124 print_dscp(u_int8_t dscp, int invert, int numeric)
    125 {
    126 	if (invert)
    127 		fputc('!', stdout);
    128 
    129  	printf("0x%02x ", dscp);
    130 }
    131 
    132 /* Prints out the matchinfo. */
    133 static void
    134 print(const struct ipt_ip *ip,
    135       const struct ipt_entry_match *match,
    136       int numeric)
    137 {
    138 	const struct ipt_dscp_info *dinfo =
    139 		(const struct ipt_dscp_info *)match->data;
    140 	printf("DSCP match ");
    141 	print_dscp(dinfo->dscp, dinfo->invert, numeric);
    142 }
    143 
    144 /* Saves the union ipt_matchinfo in parsable form to stdout. */
    145 static void
    146 save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
    147 {
    148 	const struct ipt_dscp_info *dinfo =
    149 		(const struct ipt_dscp_info *)match->data;
    150 
    151 	printf("--dscp ");
    152 	print_dscp(dinfo->dscp, dinfo->invert, 1);
    153 }
    154 
    155 static struct iptables_match dscp = {
    156 	.next 		= NULL,
    157 	.name 		= "dscp",
    158 	.version 	= IPTABLES_VERSION,
    159 	.size 		= IPT_ALIGN(sizeof(struct ipt_dscp_info)),
    160 	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_dscp_info)),
    161 	.help		= &help,
    162 	.parse		= &parse,
    163 	.final_check	= &final_check,
    164 	.print		= &print,
    165 	.save		= &save,
    166 	.extra_opts	= opts
    167 };
    168 
    169 void ipt_2dscp_init(void)
    170 {
    171 	register_match(&dscp);
    172 }
    173