From e6869a8f59d779ff4d5a0984c86d80db70784962 Mon Sep 17 00:00:00 2001 From: Marc Boucher Date: Mon, 20 Mar 2000 06:03:29 +0000 Subject: reorganized tree after kernel merge --- extensions/Makefile | 14 ++ extensions/libipt_DNAT.c | 244 +++++++++++++++++++++++ extensions/libipt_LOG.c | 260 ++++++++++++++++++++++++ extensions/libipt_MARK.c | 120 +++++++++++ extensions/libipt_MASQUERADE.c | 166 ++++++++++++++++ extensions/libipt_REDIRECT.c | 166 ++++++++++++++++ extensions/libipt_REJECT.c | 159 +++++++++++++++ extensions/libipt_SNAT.c | 244 +++++++++++++++++++++++ extensions/libipt_TOS.c | 173 ++++++++++++++++ extensions/libipt_icmp.c | 295 +++++++++++++++++++++++++++ extensions/libipt_limit.c | 196 ++++++++++++++++++ extensions/libipt_mac.c | 144 ++++++++++++++ extensions/libipt_mark.c | 128 ++++++++++++ extensions/libipt_multiport.c | 262 ++++++++++++++++++++++++ extensions/libipt_owner.c | 219 ++++++++++++++++++++ extensions/libipt_standard.c | 67 +++++++ extensions/libipt_state.c | 162 +++++++++++++++ extensions/libipt_tcp.c | 439 +++++++++++++++++++++++++++++++++++++++++ extensions/libipt_tos.c | 171 ++++++++++++++++ extensions/libipt_udp.c | 252 +++++++++++++++++++++++ extensions/libipt_unclean.c | 66 +++++++ 21 files changed, 3947 insertions(+) create mode 100644 extensions/Makefile create mode 100644 extensions/libipt_DNAT.c create mode 100644 extensions/libipt_LOG.c create mode 100644 extensions/libipt_MARK.c create mode 100644 extensions/libipt_MASQUERADE.c create mode 100644 extensions/libipt_REDIRECT.c create mode 100644 extensions/libipt_REJECT.c create mode 100644 extensions/libipt_SNAT.c create mode 100644 extensions/libipt_TOS.c create mode 100644 extensions/libipt_icmp.c create mode 100644 extensions/libipt_limit.c create mode 100644 extensions/libipt_mac.c create mode 100644 extensions/libipt_mark.c create mode 100644 extensions/libipt_multiport.c create mode 100644 extensions/libipt_owner.c create mode 100644 extensions/libipt_standard.c create mode 100644 extensions/libipt_state.c create mode 100644 extensions/libipt_tcp.c create mode 100644 extensions/libipt_tos.c create mode 100644 extensions/libipt_udp.c create mode 100644 extensions/libipt_unclean.c (limited to 'extensions') diff --git a/extensions/Makefile b/extensions/Makefile new file mode 100644 index 00000000..8e0dec1c --- /dev/null +++ b/extensions/Makefile @@ -0,0 +1,14 @@ +#! /usr/bin/make + +PF_EXT_SLIB:=tcp udp icmp mac limit standard REJECT LOG unclean state multiport tos TOS mark MARK owner SNAT DNAT MASQUERADE REDIRECT +SHARED_LIBS+=$(foreach T,$(PF_EXT_SLIB),extensions/libipt_$(T).so) +EXTRA_INSTALLS+=$(foreach T, $(PF_EXT_SLIB), $(DESTDIR)$(LIBDIR)/iptables/libipt_$(T).so) + +ifndef TOPLEVEL_INCLUDED +local: + cd .. && $(MAKE) $(SHARED_LIBS) +endif + +$(DESTDIR)$(LIBDIR)/iptables/libipt_%.so: extensions/libipt_%.so + @[ -d $(DESTDIR)$(LIBDIR)/iptables ] || mkdir -p $(DESTDIR)$(LIBDIR)/iptables + cp $< $@ diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c new file mode 100644 index 00000000..e3c37222 --- /dev/null +++ b/extensions/libipt_DNAT.c @@ -0,0 +1,244 @@ +/* Shared library add-on to iptables to add destination-NAT support. */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Dest NAT data consists of a multi-range, indicating where to map + to. */ +struct ipt_natinfo +{ + struct ipt_entry_target t; + struct ip_nat_multi_range mr; +}; + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"DNAT v%s options:\n" +" --to-destination [-][:port-port]\n" +" Address to map destination to.\n" +" (You can use this more than once)\n\n", +NETFILTER_VERSION); +} + +static struct option opts[] = { + { "to-destination", 1, 0, '1' }, + { 0 } +}; + +/* Initialize the target. */ +static void +init(struct ipt_entry_target *t, unsigned int *nfcache) +{ + /* Can't cache this */ + *nfcache |= NFC_UNKNOWN; +} + +static struct ipt_natinfo * +append_range(struct ipt_natinfo *info, const struct ip_nat_range *range) +{ + unsigned int size; + + /* One rangesize already in struct ipt_natinfo */ + size = IPT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range)); + + info = realloc(info, size); + if (!info) + exit_error(OTHER_PROBLEM, "Out of memory\n"); + + info->t.target_size = size; + info->mr.range[info->mr.rangesize] = *range; + info->mr.rangesize++; + + return info; +} + +/* Ranges expected in network order. */ +static struct ipt_entry_target * +parse_to(char *arg, int portok, struct ipt_natinfo *info) +{ + struct ip_nat_range range; + char *colon, *dash; + struct in_addr *ip; + + memset(&range, 0, sizeof(range)); + colon = strchr(arg, ':'); + + if (colon) { + int port; + + if (!portok) + exit_error(PARAMETER_PROBLEM, + "Need TCP or UDP with port specification"); + + range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + + port = atoi(colon+1); + if (port == 0 || port > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", colon+1); + + dash = strchr(colon, '-'); + if (!dash) { + range.min.tcp.port + = range.max.tcp.port + = htons(port); + } else { + int maxport; + + maxport = atoi(dash + 1); + if (maxport == 0 || maxport > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", dash+1); + if (maxport < port) + /* People are stupid. */ + exit_error(PARAMETER_PROBLEM, + "Port range `%s' funky\n", colon+1); + range.min.tcp.port = htons(port); + range.max.tcp.port = htons(maxport); + } + /* Starts with a colon? No IP info...*/ + if (colon == arg) + return &(append_range(info, &range)->t); + *colon = '\0'; + } + + range.flags |= IP_NAT_RANGE_MAP_IPS; + dash = strchr(arg, '-'); + if (colon && dash && dash > colon) + dash = NULL; + + if (dash) + *dash = '\0'; + + ip = dotted_to_addr(arg); + if (!ip) + exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", + arg); + range.min_ip = ip->s_addr; + if (dash) { + ip = dotted_to_addr(dash+1); + if (!ip) + exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", + dash+1); + range.max_ip = ip->s_addr; + } else + range.max_ip = range.min_ip; + + return &(append_range(info, &range)->t); +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + struct ipt_entry_target **target) +{ + struct ipt_natinfo *info = (void *)*target; + int portok; + + if (entry->ip.proto == IPPROTO_TCP + || entry->ip.proto == IPPROTO_UDP) + portok = 1; + else + portok = 0; + + switch (c) { + case '1': + if (check_inverse(optarg, &invert)) + exit_error(PARAMETER_PROBLEM, + "Unexpected `!' after --to-destination"); + + *target = parse_to(optarg, portok, info); + *flags = 1; + return 1; + + default: + return 0; + } +} + +/* Final check; must have specfied --to-source. */ +static void final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, + "You must specify --to-destination"); +} + +static void print_range(const struct ip_nat_range *r) +{ + if (r->flags & IP_NAT_RANGE_MAP_IPS) { + struct in_addr a; + + a.s_addr = r->min_ip; + printf("%s", addr_to_dotted(&a)); + if (r->max_ip != r->min_ip) { + a.s_addr = r->max_ip; + printf("-%s", addr_to_dotted(&a)); + } + } + if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { + printf(":"); + printf("%hu", ntohs(r->min.tcp.port)); + if (r->max.tcp.port != r->min.tcp.port) + printf("-%hu", ntohs(r->max.tcp.port)); + } +} + +/* Prints out the targinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_target *target, + int numeric) +{ + struct ipt_natinfo *info = (void *)target; + unsigned int i = 0; + + printf("to:"); + for (i = 0; i < info->mr.rangesize; i++) { + print_range(&info->mr.range[i]); + printf(" "); + } +} + +/* Saves the union ipt_targinfo in parsable form to stdout. */ +static void +save(const struct ipt_ip *ip, const struct ipt_entry_target *target) +{ + struct ipt_natinfo *info = (void *)target; + unsigned int i = 0; + + for (i = 0; i < info->mr.rangesize; i++) { + printf("--to-destination "); + print_range(&info->mr.range[i]); + printf(" "); + } +} + +struct iptables_target dnat += { NULL, + "DNAT", + NETFILTER_VERSION, + sizeof(struct ip_nat_multi_range), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_target(&dnat); +} diff --git a/extensions/libipt_LOG.c b/extensions/libipt_LOG.c new file mode 100644 index 00000000..cab5739d --- /dev/null +++ b/extensions/libipt_LOG.c @@ -0,0 +1,260 @@ +/* Shared library add-on to iptables to add LOG support. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_DEFAULT_LEVEL LOG_WARNING + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"LOG v%s options:\n" +" --log-level level Level of logging (numeric or see syslog.conf)\n" +" --log-prefix prefix Prefix log messages with this prefix.\n\n" +" --log-tcp-sequence Log TCP sequence numbers.\n\n" +" --log-tcp-options Log TCP options.\n\n" +" --log-ip-options Log IP options.\n\n", +NETFILTER_VERSION); +} + +static struct option opts[] = { + { "log-level", 1, 0, '!' }, + { "log-prefix", 1, 0, '#' }, + { "log-tcp-sequence", 0, 0, '1' }, + { "log-tcp-options", 0, 0, '2' }, + { "log-ip-options", 0, 0, '3' }, + { 0 } +}; + +/* Initialize the target. */ +static void +init(struct ipt_entry_target *t, unsigned int *nfcache) +{ + struct ipt_log_info *loginfo = (struct ipt_log_info *)t->data; + + loginfo->level = LOG_DEFAULT_LEVEL; + + /* Can't cache this */ + *nfcache |= NFC_UNKNOWN; +} + +struct ipt_log_names { + const char *name; + unsigned int level; +}; + +static struct ipt_log_names ipt_log_names[] += { { "alert", LOG_ALERT }, + { "crit", LOG_CRIT }, + { "debug", LOG_DEBUG }, + { "emerg", LOG_EMERG }, + { "error", LOG_ERR }, /* DEPRECATED */ + { "info", LOG_INFO }, + { "notice", LOG_NOTICE }, + { "panic", LOG_EMERG }, /* DEPRECATED */ + { "warning", LOG_WARNING } +}; + +static u_int8_t +parse_level(const char *level) +{ + int lev; + + lev = string_to_number(level, 0, 7); + if (lev == -1) { + unsigned int i = 0; + + for (i = 0; + i < sizeof(ipt_log_names) / sizeof(struct ipt_log_names); + i++) { + if (strncasecmp(level, ipt_log_names[i].name, + strlen(level)) == 0) { + if (lev != -1) + exit_error(PARAMETER_PROBLEM, + "log-level `%s' ambiguous", + level); + lev = ipt_log_names[i].level; + } + } + + if (lev == -1) + exit_error(PARAMETER_PROBLEM, + "log-level `%s' unknown", level); + } + + return (u_int8_t)lev; +} + +#define IPT_LOG_OPT_LEVEL 0x01 +#define IPT_LOG_OPT_PREFIX 0x02 +#define IPT_LOG_OPT_TCPSEQ 0x04 +#define IPT_LOG_OPT_TCPOPT 0x08 +#define IPT_LOG_OPT_IPOPT 0x10 + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + struct ipt_entry_target **target) +{ + struct ipt_log_info *loginfo = (struct ipt_log_info *)(*target)->data; + + switch (c) { + case '!': + if (*flags & IPT_LOG_OPT_LEVEL) + exit_error(PARAMETER_PROBLEM, + "Can't specify --log-level twice"); + + if (check_inverse(optarg, &invert)) + exit_error(PARAMETER_PROBLEM, + "Unexpected `!' after --log-level"); + + loginfo->level = parse_level(optarg); + *flags |= IPT_LOG_OPT_LEVEL; + break; + + case '#': + if (*flags & IPT_LOG_OPT_PREFIX) + exit_error(PARAMETER_PROBLEM, + "Can't specify --log-prefix twice"); + + if (check_inverse(optarg, &invert)) + exit_error(PARAMETER_PROBLEM, + "Unexpected `!' after --log-prefix"); + + if (strlen(optarg) > sizeof(loginfo->prefix) - 1) + exit_error(PARAMETER_PROBLEM, + "Maximum prefix length %u for --log-prefix", + sizeof(loginfo->prefix) - 1); + + strcpy(loginfo->prefix, optarg); + *flags |= IPT_LOG_OPT_PREFIX; + break; + + case '1': + if (*flags & IPT_LOG_OPT_TCPSEQ) + exit_error(PARAMETER_PROBLEM, + "Can't specify --log-tcp-sequence " + "twice"); + + loginfo->logflags |= IPT_LOG_TCPSEQ; + *flags |= IPT_LOG_OPT_TCPSEQ; + break; + + case '2': + if (*flags & IPT_LOG_OPT_TCPOPT) + exit_error(PARAMETER_PROBLEM, + "Can't specify --log-tcp-options twice"); + + loginfo->logflags |= IPT_LOG_TCPOPT; + *flags |= IPT_LOG_OPT_TCPOPT; + break; + + case '3': + if (*flags & IPT_LOG_OPT_IPOPT) + exit_error(PARAMETER_PROBLEM, + "Can't specify --log-ip-options twice"); + + loginfo->logflags |= IPT_LOG_IPOPT; + *flags |= IPT_LOG_OPT_IPOPT; + break; + + default: + return 0; + } + + return 1; +} + +/* Final check; nothing. */ +static void final_check(unsigned int flags) +{ +} + +/* Prints out the targinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_target *target, + int numeric) +{ + const struct ipt_log_info *loginfo + = (const struct ipt_log_info *)target->data; + unsigned int i = 0; + + printf("LOG "); + if (numeric) + printf("flags %u level %u ", + loginfo->logflags, loginfo->level); + else { + for (i = 0; + i < sizeof(ipt_log_names) / sizeof(struct ipt_log_names); + i++) { + if (loginfo->level == ipt_log_names[i].level) { + printf("level %s ", ipt_log_names[i].name); + break; + } + } + if (i == sizeof(ipt_log_names) / sizeof(struct ipt_log_names)) + printf("UNKNOWN level %u ", loginfo->level); + if (loginfo->logflags & IPT_LOG_TCPSEQ) + printf("tcp-sequence "); + if (loginfo->logflags & IPT_LOG_TCPOPT) + printf("tcp-options "); + if (loginfo->logflags & IPT_LOG_IPOPT) + printf("ip-options "); + if (loginfo->logflags & ~(IPT_LOG_MASK)) + printf("unknown-flags "); + } + + if (strcmp(loginfo->prefix, "") != 0) + printf("prefix `%s' ", loginfo->prefix); +} + +/* Saves the union ipt_targinfo in parsable form to stdout. */ +static void +save(const struct ipt_ip *ip, const struct ipt_entry_target *target) +{ + const struct ipt_log_info *loginfo + = (const struct ipt_log_info *)target->data; + + if (strcmp(loginfo->prefix, "") != 0) + printf("--log-prefix %s ", loginfo->prefix); + + if (loginfo->level != LOG_DEFAULT_LEVEL) + printf("--log-level %u ", loginfo->level); + + if (loginfo->logflags & IPT_LOG_TCPSEQ) + printf("--log-tcp-sequence "); + if (loginfo->logflags & IPT_LOG_TCPOPT) + printf("--log-tcp-options "); + if (loginfo->logflags & IPT_LOG_IPOPT) + printf("--log-ip-options "); +} + +struct iptables_target log += { NULL, + "LOG", + NETFILTER_VERSION, + sizeof(struct ipt_log_info), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_target(&log); +} diff --git a/extensions/libipt_MARK.c b/extensions/libipt_MARK.c new file mode 100644 index 00000000..ef5a60d5 --- /dev/null +++ b/extensions/libipt_MARK.c @@ -0,0 +1,120 @@ +/* Shared library add-on to iptables to add MARK target support. */ +#include +#include +#include +#include + +#include +#include +#include + +struct markinfo { + struct ipt_entry_target t; + struct ipt_mark_target_info mark; +}; + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"MARK target v%s options:\n" +" --set-mark value Set nfmark value\n" +"\n", +NETFILTER_VERSION); +} + +static struct option opts[] = { + { "set-mark", 1, 0, '1' }, + { 0 } +}; + +/* Initialize the target. */ +static void +init(struct ipt_entry_target *t, unsigned int *nfcache) +{ +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + struct ipt_entry_target **target) +{ + struct ipt_mark_target_info *markinfo + = (struct ipt_mark_target_info *)(*target)->data; + + switch (c) { + char *end; + case '1': + markinfo->mark = strtoul(optarg, &end, 0); + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg); + if (*flags) + exit_error(PARAMETER_PROBLEM, + "MARK target: Can't specify --set-mark twice"); + *flags = 1; + break; + + default: + return 0; + } + + return 1; +} + +static void +final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, + "MARK target: Parameter --set-mark is required"); +} + +static void +print_mark(unsigned long mark, int numeric) +{ + printf("0x%lx ", mark); +} + +/* Prints out the targinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_target *target, + int numeric) +{ + const struct ipt_mark_target_info *markinfo = + (const struct ipt_mark_target_info *)target->data; + printf("MARK set "); + print_mark(markinfo->mark, numeric); +} + +/* Saves the union ipt_targinfo in parsable form to stdout. */ +static void +save(const struct ipt_ip *ip, const struct ipt_entry_target *target) +{ + const struct ipt_mark_target_info *markinfo = + (const struct ipt_mark_target_info *)target->data; + + printf("--set-mark 0x%lx ", markinfo->mark); +} + +struct iptables_target mark += { NULL, + "MARK", + NETFILTER_VERSION, + sizeof(struct ipt_mark_target_info), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_target(&mark); +} diff --git a/extensions/libipt_MASQUERADE.c b/extensions/libipt_MASQUERADE.c new file mode 100644 index 00000000..a1151bbc --- /dev/null +++ b/extensions/libipt_MASQUERADE.c @@ -0,0 +1,166 @@ +/* Shared library add-on to iptables to add masquerade support. */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"MASQUERADE v%s options:\n" +" --to-ports [-]\n" +" Port (range) to map to.\n\n", +NETFILTER_VERSION); +} + +static struct option opts[] = { + { "to-ports", 1, 0, '1' }, + { 0 } +}; + +/* Initialize the target. */ +static void +init(struct ipt_entry_target *t, unsigned int *nfcache) +{ + struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data; + + /* Actually, it's 0, but it's ignored at the moment. */ + mr->rangesize = 1; + + /* Can't cache this */ + *nfcache |= NFC_UNKNOWN; +} + +/* Parses ports */ +static void +parse_ports(const char *arg, struct ip_nat_multi_range *mr) +{ + const char *dash; + int port; + + mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + + port = atoi(arg); + if (port == 0 || port > 65535) + exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", arg); + + dash = strchr(arg, '-'); + if (!dash) { + mr->range[0].min.tcp.port + = mr->range[0].max.tcp.port + = port; + } else { + int maxport; + + maxport = atoi(dash + 1); + if (maxport == 0 || maxport > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", dash+1); + if (maxport < port) + /* People are stupid. Present reader excepted. */ + exit_error(PARAMETER_PROBLEM, + "Port range `%s' funky\n", arg); + mr->range[0].min.tcp.port = port; + mr->range[0].max.tcp.port = maxport; + } +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + struct ipt_entry_target **target) +{ + int portok; + struct ip_nat_multi_range *mr + = (struct ip_nat_multi_range *)(*target)->data; + + if (entry->ip.proto == IPPROTO_TCP + || entry->ip.proto == IPPROTO_UDP) + portok = 1; + else + portok = 0; + + switch (c) { + case '1': + if (!portok) + exit_error(PARAMETER_PROBLEM, + "Need TCP or UDP with port specification"); + + if (check_inverse(optarg, &invert)) + exit_error(PARAMETER_PROBLEM, + "Unexpected `!' after --to-ports"); + + parse_ports(optarg, mr); + return 1; + + default: + return 0; + } +} + +/* Final check; don't care. */ +static void final_check(unsigned int flags) +{ +} + +/* Prints out the targinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_target *target, + int numeric) +{ + struct ip_nat_multi_range *mr + = (struct ip_nat_multi_range *)target->data; + struct ip_nat_range *r = &mr->range[0]; + + printf("MASQUERADE "); + if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { + printf("%hu", r->min.tcp.port); + if (r->max.tcp.port != r->min.tcp.port) + printf("-%hu", r->max.tcp.port); + printf(" "); + } +} + +/* Saves the union ipt_targinfo in parsable form to stdout. */ +static void +save(const struct ipt_ip *ip, const struct ipt_entry_target *target) +{ + struct ip_nat_multi_range *mr + = (struct ip_nat_multi_range *)target->data; + struct ip_nat_range *r = &mr->range[0]; + + if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { + printf("%hu", r->min.tcp.port); + if (r->max.tcp.port != r->min.tcp.port) + printf("-%hu", r->max.tcp.port); + printf(" "); + } +} + +struct iptables_target masq += { NULL, + "MASQUERADE", + NETFILTER_VERSION, + sizeof(struct ip_nat_multi_range), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_target(&masq); +} diff --git a/extensions/libipt_REDIRECT.c b/extensions/libipt_REDIRECT.c new file mode 100644 index 00000000..aaafaaf1 --- /dev/null +++ b/extensions/libipt_REDIRECT.c @@ -0,0 +1,166 @@ +/* Shared library add-on to iptables to add redirect support. */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"REDIRECT v%s options:\n" +" --to-ports [-]\n" +" Port (range) to map to.\n\n", +NETFILTER_VERSION); +} + +static struct option opts[] = { + { "to-ports", 1, 0, '1' }, + { 0 } +}; + +/* Initialize the target. */ +static void +init(struct ipt_entry_target *t, unsigned int *nfcache) +{ + struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data; + + /* Actually, it's 0, but it's ignored at the moment. */ + mr->rangesize = 1; + + /* Can't cache this */ + *nfcache |= NFC_UNKNOWN; +} + +/* Parses ports */ +static void +parse_ports(const char *arg, struct ip_nat_multi_range *mr) +{ + const char *dash; + int port; + + mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + + port = atoi(arg); + if (port == 0 || port > 65535) + exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", arg); + + dash = strchr(arg, '-'); + if (!dash) { + mr->range[0].min.tcp.port + = mr->range[0].max.tcp.port + = port; + } else { + int maxport; + + maxport = atoi(dash + 1); + if (maxport == 0 || maxport > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", dash+1); + if (maxport < port) + /* People are stupid. */ + exit_error(PARAMETER_PROBLEM, + "Port range `%s' funky\n", arg); + mr->range[0].min.tcp.port = port; + mr->range[0].max.tcp.port = maxport; + } +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + struct ipt_entry_target **target) +{ + struct ip_nat_multi_range *mr + = (struct ip_nat_multi_range *)(*target)->data; + int portok; + + if (entry->ip.proto == IPPROTO_TCP + || entry->ip.proto == IPPROTO_UDP) + portok = 1; + else + portok = 0; + + switch (c) { + case '1': + if (!portok) + exit_error(PARAMETER_PROBLEM, + "Need TCP or UDP with port specification"); + + if (check_inverse(optarg, &invert)) + exit_error(PARAMETER_PROBLEM, + "Unexpected `!' after --to-ports"); + + parse_ports(optarg, mr); + return 1; + + default: + return 0; + } +} + +/* Final check; don't care. */ +static void final_check(unsigned int flags) +{ +} + +/* Prints out the targinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_target *target, + int numeric) +{ + struct ip_nat_multi_range *mr + = (struct ip_nat_multi_range *)target->data; + struct ip_nat_range *r = &mr->range[0]; + + printf("REDIRECT "); + if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { + printf("%hu", r->min.tcp.port); + if (r->max.tcp.port != r->min.tcp.port) + printf("-%hu", r->max.tcp.port); + printf(" "); + } +} + +/* Saves the union ipt_targinfo in parsable form to stdout. */ +static void +save(const struct ipt_ip *ip, const struct ipt_entry_target *target) +{ + struct ip_nat_multi_range *mr + = (struct ip_nat_multi_range *)target->data; + struct ip_nat_range *r = &mr->range[0]; + + if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { + printf("%hu", r->min.tcp.port); + if (r->max.tcp.port != r->min.tcp.port) + printf("-%hu", r->max.tcp.port); + printf(" "); + } +} + +struct iptables_target redir += { NULL, + "REDIRECT", + NETFILTER_VERSION, + sizeof(struct ip_nat_multi_range), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_target(&redir); +} diff --git a/extensions/libipt_REJECT.c b/extensions/libipt_REJECT.c new file mode 100644 index 00000000..e3365873 --- /dev/null +++ b/extensions/libipt_REJECT.c @@ -0,0 +1,159 @@ +/* Shared library add-on to iptables to add customized REJECT support. + * + * (C) 2000 Jozsef Kadlecsik + */ +#include +#include +#include +#include +#include +#include +#include + +struct reject_names { + const char *name; + const char *alias; + enum ipt_reject_with with; + const char *desc; +}; + +static const struct reject_names reject_table[] = { + {"icmp-net-unreachable", "net-unreach", + IPT_ICMP_NET_UNREACHABLE, "ICMP network unreachable"}, + {"icmp-host-unreachable", "host-unreach", + IPT_ICMP_HOST_UNREACHABLE, "ICMP host unreachable"}, + {"icmp-port-unreachable", "port-unreach", + IPT_ICMP_PORT_UNREACHABLE, "ICMP port unreachable (default)"}, + {"icmp-proto-unreachable", "proto-unreach", + IPT_ICMP_PROT_UNREACHABLE, "ICMP protocol unreachable"}, + {"tcp-reset", "rst", + IPT_TCP_RESET, "for TCP only: faked TCP RST"}, + {"echo-reply", "echoreply", + IPT_ICMP_ECHOREPLY, "for ICMP echo only: faked ICMP echo reply"}, +}; + +static void +print_reject_types() +{ + unsigned int i; + + printf("Valid reject types:\n"); + + for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) { + printf(" %-25s\t%s\n", reject_table[i].name, reject_table[i].desc); + printf(" %-25s\talias\n", reject_table[i].alias); + } + printf("\n"); +} + +/* Saves the union ipt_targinfo in parsable form to stdout. */ + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"REJECT options:\n" +"--reject-with type drop input packet and send back\n" +" a reply packet according to type:\n"); + + print_reject_types(); +} + +static struct option opts[] = { + { "reject-with", 1, 0, '1' }, + { 0 } +}; + +/* Allocate and initialize the target. */ +static void +init(struct ipt_entry_target *t, unsigned int *nfcache) +{ + struct ipt_reject_info *reject = (struct ipt_reject_info *)t->data; + + /* default */ + reject->with = IPT_ICMP_PORT_UNREACHABLE; + + /* Can't cache this */ + *nfcache |= NFC_UNKNOWN; +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + struct ipt_entry_target **target) +{ + struct ipt_reject_info *reject = (struct ipt_reject_info *)(*target)->data; + unsigned int limit = sizeof(reject_table)/sizeof(struct reject_names); + unsigned int i; + + switch(c) { + case '1': + if (check_inverse(optarg, &invert)) + exit_error(PARAMETER_PROBLEM, + "Unexpected `!' after --reject-with"); + for (i = 0; i < limit; i++) { + if ((strncasecmp(reject_table[i].name, optarg, strlen(optarg)) == 0) + || (strncasecmp(reject_table[i].alias, optarg, strlen(optarg)) == 0)) { + reject->with = reject_table[i].with; + return 1; + } + } + exit_error(PARAMETER_PROBLEM, "unknown reject type `%s'",optarg); + default: + /* Fall through */ + } + return 0; +} + +/* Final check; nothing. */ +static void final_check(unsigned int flags) +{ +} + +/* Prints out ipt_reject_info. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_target *target, + int numeric) +{ + const struct ipt_reject_info *reject + = (const struct ipt_reject_info *)target->data; + unsigned int i; + + for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) { + if (reject_table[i].with == reject->with) + break; + } + printf("reject-with %s ", reject_table[i].name); +} + +/* Saves ipt_reject in parsable form to stdout. */ +static void save(const struct ipt_ip *ip, const struct ipt_entry_target *target) +{ + const struct ipt_reject_info *reject + = (const struct ipt_reject_info *)target->data; + + printf("--reject-with %s ", reject_table[reject->with].name); +} + +struct iptables_target reject += { NULL, + "REJECT", + NETFILTER_VERSION, + sizeof(struct ipt_reject_info), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_target(&reject); +} diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c new file mode 100644 index 00000000..86ba39b9 --- /dev/null +++ b/extensions/libipt_SNAT.c @@ -0,0 +1,244 @@ +/* Shared library add-on to iptables to add source-NAT support. */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Source NAT data consists of a multi-range, indicating where to map + to. */ +struct ipt_natinfo +{ + struct ipt_entry_target t; + struct ip_nat_multi_range mr; +}; + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"SNAT v%s options:\n" +" --to-source [-][:port-port]\n" +" Address to map source to.\n" +" (You can use this more than once)\n\n", +NETFILTER_VERSION); +} + +static struct option opts[] = { + { "to-source", 1, 0, '1' }, + { 0 } +}; + +/* Initialize the target. */ +static void +init(struct ipt_entry_target *t, unsigned int *nfcache) +{ + /* Can't cache this */ + *nfcache |= NFC_UNKNOWN; +} + +static struct ipt_natinfo * +append_range(struct ipt_natinfo *info, const struct ip_nat_range *range) +{ + unsigned int size; + + /* One rangesize already in struct ipt_natinfo */ + size = IPT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range)); + + info = realloc(info, size); + if (!info) + exit_error(OTHER_PROBLEM, "Out of memory\n"); + + info->t.target_size = size; + info->mr.range[info->mr.rangesize] = *range; + info->mr.rangesize++; + + return info; +} + +/* Ranges expected in network order. */ +static struct ipt_entry_target * +parse_to(char *arg, int portok, struct ipt_natinfo *info) +{ + struct ip_nat_range range; + char *colon, *dash; + struct in_addr *ip; + + memset(&range, 0, sizeof(range)); + colon = strchr(arg, ':'); + + if (colon) { + int port; + + if (!portok) + exit_error(PARAMETER_PROBLEM, + "Need TCP or UDP with port specification"); + + range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + + port = atoi(colon+1); + if (port == 0 || port > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", colon+1); + + dash = strchr(colon, '-'); + if (!dash) { + range.min.tcp.port + = range.max.tcp.port + = htons(port); + } else { + int maxport; + + maxport = atoi(dash + 1); + if (maxport == 0 || maxport > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", dash+1); + if (maxport < port) + /* People are stupid. */ + exit_error(PARAMETER_PROBLEM, + "Port range `%s' funky\n", colon+1); + range.min.tcp.port = htons(port); + range.max.tcp.port = htons(maxport); + } + /* Starts with a colon? No IP info...*/ + if (colon == arg) + return &(append_range(info, &range)->t); + *colon = '\0'; + } + + range.flags |= IP_NAT_RANGE_MAP_IPS; + dash = strchr(arg, '-'); + if (colon && dash && dash > colon) + dash = NULL; + + if (dash) + *dash = '\0'; + + ip = dotted_to_addr(arg); + if (!ip) + exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", + arg); + range.min_ip = ip->s_addr; + if (dash) { + ip = dotted_to_addr(dash+1); + if (!ip) + exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", + dash+1); + range.max_ip = ip->s_addr; + } else + range.max_ip = range.min_ip; + + return &(append_range(info, &range)->t); +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + struct ipt_entry_target **target) +{ + struct ipt_natinfo *info = (void *)*target; + int portok; + + if (entry->ip.proto == IPPROTO_TCP + || entry->ip.proto == IPPROTO_UDP) + portok = 1; + else + portok = 0; + + switch (c) { + case '1': + if (check_inverse(optarg, &invert)) + exit_error(PARAMETER_PROBLEM, + "Unexpected `!' after --to-source"); + + *target = parse_to(optarg, portok, info); + *flags = 1; + return 1; + + default: + return 0; + } +} + +/* Final check; must have specfied --to-source. */ +static void final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, + "You must specify --to-source"); +} + +static void print_range(const struct ip_nat_range *r) +{ + if (r->flags & IP_NAT_RANGE_MAP_IPS) { + struct in_addr a; + + a.s_addr = r->min_ip; + printf("%s", addr_to_dotted(&a)); + if (r->max_ip != r->min_ip) { + a.s_addr = r->max_ip; + printf("-%s", addr_to_dotted(&a)); + } + } + if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { + printf(":"); + printf("%hu", ntohs(r->min.tcp.port)); + if (r->max.tcp.port != r->min.tcp.port) + printf("-%hu", ntohs(r->max.tcp.port)); + } +} + +/* Prints out the targinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_target *target, + int numeric) +{ + struct ipt_natinfo *info = (void *)target; + unsigned int i = 0; + + printf("to:"); + for (i = 0; i < info->mr.rangesize; i++) { + print_range(&info->mr.range[i]); + printf(" "); + } +} + +/* Saves the union ipt_targinfo in parsable form to stdout. */ +static void +save(const struct ipt_ip *ip, const struct ipt_entry_target *target) +{ + struct ipt_natinfo *info = (void *)target; + unsigned int i = 0; + + for (i = 0; i < info->mr.rangesize; i++) { + printf("--to-source "); + print_range(&info->mr.range[i]); + printf(" "); + } +} + +struct iptables_target snat += { NULL, + "SNAT", + NETFILTER_VERSION, + sizeof(struct ip_nat_multi_range), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_target(&snat); +} diff --git a/extensions/libipt_TOS.c b/extensions/libipt_TOS.c new file mode 100644 index 00000000..4a8e91ba --- /dev/null +++ b/extensions/libipt_TOS.c @@ -0,0 +1,173 @@ +/* Shared library add-on to iptables to add TOS target support. */ +#include +#include +#include +#include + +#include +#include +#include + +struct tosinfo { + struct ipt_entry_target t; + struct ipt_tos_target_info tos; +}; + +/* TOS names and values. */ +struct TOS_value +{ + unsigned char TOS; + const char *name; +} TOS_values[] = { + { IPTOS_LOWDELAY, "Minimize-Delay" }, + { IPTOS_THROUGHPUT, "Maximize-Throughput" }, + { IPTOS_RELIABILITY, "Maximize-Reliability" }, + { IPTOS_MINCOST, "Minimize-Cost" }, + { IPTOS_NORMALSVC, "Normal-Service" }, +}; + +/* Function which prints out usage message. */ +static void +help(void) +{ + unsigned int i; + + printf( +"TOS target v%s options:\n" +" --set-tos value Set Type of Service field to one of the\n" +" following numeric or descriptive values:\n", +NETFILTER_VERSION); + + for (i = 0; i < sizeof(TOS_values)/sizeof(struct TOS_value);i++) + printf(" %s %u (0x%02x)\n", + TOS_values[i].name, + TOS_values[i].TOS, + TOS_values[i].TOS); + fputc('\n', stdout); +} + +static struct option opts[] = { + { "set-tos", 1, 0, '1' }, + { 0 } +}; + +/* Initialize the target. */ +static void +init(struct ipt_entry_target *t, unsigned int *nfcache) +{ +} + +static void +parse_tos(const unsigned char *s, struct ipt_tos_target_info *info) +{ + unsigned int i; + int tos = string_to_number(s, 0, 255); + + if (tos != -1) { + if (tos == IPTOS_LOWDELAY + || tos == IPTOS_THROUGHPUT + || tos == IPTOS_RELIABILITY + || tos == IPTOS_MINCOST + || tos == IPTOS_NORMALSVC) { + info->tos = (u_int8_t )tos; + return; + } + } else { + for (i = 0; itos = TOS_values[i].TOS; + return; + } + } + exit_error(PARAMETER_PROBLEM, "Bad TOS value `%s'", s); +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + struct ipt_entry_target **target) +{ + struct ipt_tos_target_info *tosinfo + = (struct ipt_tos_target_info *)(*target)->data; + + switch (c) { + case '1': + if (*flags) + exit_error(PARAMETER_PROBLEM, + "TOS target: Cant specify --set-tos twice"); + parse_tos(optarg, tosinfo); + *flags = 1; + break; + + default: + return 0; + } + + return 1; +} + +static void +final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, + "TOS target: Parameter --set-tos is required"); +} + +static void +print_tos(u_int8_t tos, int numeric) +{ + unsigned int i; + + if (!numeric) { + for (i = 0; idata; + printf("TOS set "); + print_tos(tosinfo->tos, numeric); +} + +/* Saves the union ipt_targinfo in parsable form to stdout. */ +static void +save(const struct ipt_ip *ip, const struct ipt_entry_target *target) +{ + const struct ipt_tos_target_info *tosinfo = + (const struct ipt_tos_target_info *)target->data; + + printf("--set-tos 0x%02x ", tosinfo->tos); +} + +struct iptables_target tos += { NULL, + "TOS", + NETFILTER_VERSION, + sizeof(struct ipt_tos_target_info), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_target(&tos); +} diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c new file mode 100644 index 00000000..65857ce3 --- /dev/null +++ b/extensions/libipt_icmp.c @@ -0,0 +1,295 @@ +/* Shared library add-on to iptables to add ICMP support. */ +#include +#include +#include +#include +#include +#include +#include + +struct icmp_names { + const char *name; + u_int8_t type; + u_int8_t code_min, code_max; +}; + +static const struct icmp_names icmp_codes[] = { + { "echo-reply", 0, 0, 0xFF }, + /* Alias */ { "pong", 0, 0, 0xFF }, + + { "destination-unreachable", 3, 0, 0xFF }, + { "network-unreachable", 3, 0, 0 }, + { "host-unreachable", 3, 1, 1 }, + { "protocol-unreachable", 3, 2, 2 }, + { "port-unreachable", 3, 3, 3 }, + { "fragmentation-needed", 3, 4, 4 }, + { "source-route-failed", 3, 5, 5 }, + { "network-unknown", 3, 6, 6 }, + { "host-unknown", 3, 7, 7 }, + { "network-prohibited", 3, 9, 9 }, + { "host-prohibited", 3, 10, 10 }, + { "TOS-network-unreachable", 3, 11, 11 }, + { "TOS-host-unreachable", 3, 12, 12 }, + { "communication-prohibited", 3, 13, 13 }, + { "host-precedence-violation", 3, 14, 14 }, + { "precedence-cutoff", 3, 15, 15 }, + + { "source-quench", 4, 0, 0xFF }, + + { "redirect", 5, 0, 0xFF }, + { "network-redirect", 5, 0, 0 }, + { "host-redirect", 5, 1, 1 }, + { "TOS-network-redirect", 5, 2, 2 }, + { "TOS-host-redirect", 5, 3, 3 }, + + { "echo-request", 8, 0, 0xFF }, + /* Alias */ { "ping", 8, 0, 0xFF }, + + { "router-advertisement", 9, 0, 0xFF }, + + { "router-solicitation", 10, 0, 0xFF }, + + { "time-exceeded", 11, 0, 0xFF }, + /* Alias */ { "ttl-exceeded", 11, 0, 0xFF }, + { "ttl-zero-during-transit", 11, 0, 0 }, + { "ttl-zero-during-reassembly", 11, 1, 1 }, + + { "parameter-problem", 12, 0, 0xFF }, + { "ip-header-bad", 12, 0, 0 }, + { "required-option-missing", 12, 1, 1 }, + + { "timestamp-request", 13, 0, 0xFF }, + + { "timestamp-reply", 14, 0, 0xFF }, + + { "address-mask-request", 17, 0, 0xFF }, + + { "address-mask-reply", 18, 0, 0xFF } +}; + +static void +print_icmptypes() +{ + unsigned int i; + printf("Valid ICMP Types:"); + + for (i = 0; i < sizeof(icmp_codes)/sizeof(struct icmp_names); i++) { + if (i && icmp_codes[i].type == icmp_codes[i-1].type) { + if (icmp_codes[i].code_min == icmp_codes[i-1].code_min + && (icmp_codes[i].code_max + == icmp_codes[i-1].code_max)) + printf(" (%s)", icmp_codes[i].name); + else + printf("\n %s", icmp_codes[i].name); + } + else + printf("\n%s", icmp_codes[i].name); + } + printf("\n"); +} + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"ICMP v%s options:\n" +" --icmp-type [!] typename match icmp type\n" +" (or numeric type or type/code)\n" +"\n", NETFILTER_VERSION); + print_icmptypes(); +} + +static struct option opts[] = { + { "icmp-type", 1, 0, '1' }, + {0} +}; + +static unsigned int +parse_icmp(const char *icmptype, u_int8_t *type, u_int8_t code[]) +{ + unsigned int limit = sizeof(icmp_codes)/sizeof(struct icmp_names); + unsigned int match = limit; + unsigned int i; + + for (i = 0; i < limit; i++) { + if (strncasecmp(icmp_codes[i].name, icmptype, strlen(icmptype)) + == 0) { + if (match != limit) + exit_error(PARAMETER_PROBLEM, + "Ambiguous ICMP type `%s':" + " `%s' or `%s'?", + icmptype, + icmp_codes[match].name, + icmp_codes[i].name); + match = i; + } + } + + if (match != limit) { + *type = icmp_codes[match].type; + code[0] = icmp_codes[match].code_min; + code[1] = icmp_codes[match].code_max; + } else { + char *slash; + char buffer[strlen(icmptype) + 1]; + int number; + + strcpy(buffer, icmptype); + slash = strchr(buffer, '/'); + + if (slash) + *slash = '\0'; + + number = string_to_number(buffer, 0, 255); + if (number == -1) + exit_error(PARAMETER_PROBLEM, + "Invalid ICMP type `%s'\n", buffer); + *type = number; + if (slash) { + number = string_to_number(slash+1, 0, 255); + if (number == -1) + exit_error(PARAMETER_PROBLEM, + "Invalid ICMP code `%s'\n", + slash+1); + code[0] = code[1] = number; + } else { + code[0] = 0; + code[1] = 0xFF; + } + } + + if (code[0] == 0 && code[1] == 0xFF) + return NFC_IP_SRC_PT; + else return NFC_IP_SRC_PT | NFC_IP_DST_PT; +} + +/* Initialize the match. */ +static void +init(struct ipt_entry_match *m, unsigned int *nfcache) +{ + struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data; + + icmpinfo->code[1] = 0xFF; +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + struct ipt_icmp *icmpinfo = (struct ipt_icmp *)(*match)->data; + + switch (c) { + case '1': + if (check_inverse(optarg, &invert)) + optind++; + *nfcache |= parse_icmp(argv[optind-1], + &icmpinfo->type, + icmpinfo->code); + if (invert) + icmpinfo->invflags |= IPT_ICMP_INV; + break; + + default: + return 0; + } + + return 1; +} + +static void print_icmptype(u_int8_t type, + u_int8_t code_min, u_int8_t code_max, + int invert, + int numeric) +{ + if (!numeric) { + unsigned int i; + + for (i = 0; + i < sizeof(icmp_codes)/sizeof(struct icmp_names); + i++) { + if (icmp_codes[i].type == type + && icmp_codes[i].code_min == code_min + && icmp_codes[i].code_max == code_max) + break; + } + + if (i != sizeof(icmp_codes)/sizeof(struct icmp_names)) { + printf("%s%s ", + invert ? "!" : "", + icmp_codes[i].name); + return; + } + } + + if (invert) + printf("!"); + + printf("type %u", type); + if (code_min == 0 && code_max == 0xFF) + printf(" "); + else if (code_min == code_max) + printf(" code %u ", code_min); + else + printf(" codes %u-%u ", code_min, code_max); +} + +/* Prints out the union ipt_matchinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) +{ + const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data; + + printf("icmp "); + print_icmptype(icmp->type, icmp->code[0], icmp->code[1], + icmp->invflags & IPT_ICMP_INV, + numeric); + + if (icmp->invflags & ~IPT_ICMP_INV) + printf("Unknown invflags: 0x%X ", + icmp->invflags & ~IPT_ICMP_INV); +} + +/* Saves the match in parsable form to stdout. */ +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data; + + if (icmp->invflags & IPT_ICMP_INV) + printf("! "); + + printf("--icmp-type %u", icmp->type); + if (icmp->code[0] != 0 || icmp->code[1] != 0xFF) + printf("/%u", icmp->code[0]); + printf(" "); +} + +/* Final check; we don't care. */ +static void final_check(unsigned int flags) +{ +} + +struct iptables_match icmp += { NULL, + "icmp", + NETFILTER_VERSION, + sizeof(struct ipt_icmp), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_match(&icmp); +} diff --git a/extensions/libipt_limit.c b/extensions/libipt_limit.c new file mode 100644 index 00000000..aed63059 --- /dev/null +++ b/extensions/libipt_limit.c @@ -0,0 +1,196 @@ +/* Shared library add-on to iptables to add limit support. + * + * Jérôme de Vivie + * Hervé Eychenne + */ +#include +#include +#include +#include +#include +#include +#include + +#define IPT_LIMIT_AVG "3/hour" +#define IPT_LIMIT_BURST 5 + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"limit v%s options:\n" +"--limit avg max average match rate: default "IPT_LIMIT_AVG"\n" +" [Packets per second unless followed by \n" +" /sec /minute /hour /day postfixes]\n" +"--limit-burst number number to match in a burst, default %u\n" +"\n", NETFILTER_VERSION, IPT_LIMIT_BURST); +} + +static struct option opts[] = { + { "limit", 1, 0, '%' }, + { "limit-burst", 1, 0, '$' }, + { 0 } +}; + +static +int parse_rate(const char *rate, u_int32_t *val) +{ + const char *delim; + u_int32_t r; + u_int32_t mult = 1; /* Seconds by default. */ + + delim = strchr(rate, '/'); + if (delim) { + if (strlen(delim+1) == 0) + return 0; + + if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0) + mult = 1; + else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0) + mult = 60; + else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0) + mult = 60*60; + else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0) + mult = 24*60*60; + else + return 0; + } + r = atoi(rate); + if (!r) + return 0; + + /* This would get mapped to infinite (1/day is minimum they + can specify, so we're ok at that end). */ + if (r / mult > IPT_LIMIT_SCALE) + exit_error(PARAMETER_PROBLEM, "Rate too fast `%s'\n", rate); + + *val = IPT_LIMIT_SCALE * mult / r; + return 1; +} + +/* Initialize the match. */ +static void +init(struct ipt_entry_match *m, unsigned int *nfcache) +{ + struct ipt_rateinfo *r = (struct ipt_rateinfo *)m->data; + + parse_rate(IPT_LIMIT_AVG, &r->avg); + r->burst = IPT_LIMIT_BURST; + + /* Can't cache this */ + *nfcache |= NFC_UNKNOWN; +} + +/* FIXME: handle overflow: + if (r->avg*r->burst/r->burst != r->avg) + exit_error(PARAMETER_PROBLEM, + "Sorry: burst too large for that avg rate.\n"); +*/ + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + struct ipt_rateinfo *r = (struct ipt_rateinfo *)(*match)->data; + int num; + + switch(c) { + case '%': + if (check_inverse(optarg, &invert)) + exit_error(PARAMETER_PROBLEM, + "Unexpected `!' after --limit"); + if (!parse_rate(optarg, &r->avg)) + exit_error(PARAMETER_PROBLEM, + "bad rate `%s'", optarg); + break; + + case '$': + if (check_inverse(optarg, &invert)) + exit_error(PARAMETER_PROBLEM, + "Unexpected `!' after --limit-burst"); + + num = string_to_number(optarg, 0, 10000); + if (num <= 0) + exit_error(PARAMETER_PROBLEM, + "bad --limit-burst `%s'", optarg); + r->burst = num; + break; + + default: + return 0; + } + + return 1; +} + +/* Final check; nothing. */ +static void final_check(unsigned int flags) +{ +} + +static struct rates +{ + const char *name; + u_int32_t mult; +} rates[] = { { "day", IPT_LIMIT_SCALE*24*60*60 }, + { "hour", IPT_LIMIT_SCALE*60*60 }, + { "min", IPT_LIMIT_SCALE*60 }, + { "sec", IPT_LIMIT_SCALE } }; + +static void print_rate(u_int32_t period) +{ + unsigned int i; + + for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) { + if (period > rates[i].mult + || rates[i].mult % period != 0) + break; + } + + printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) +{ + struct ipt_rateinfo *r = (struct ipt_rateinfo *)match->data; + printf("limit: avg "); print_rate(r->avg); + printf("burst %u ", r->burst); +} + +/* FIXME: Make minimalist: only print rate if not default --RR */ +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + struct ipt_rateinfo *r = (struct ipt_rateinfo *)match->data; + + printf("--limit "); print_rate(r->avg); + if (r->burst != IPT_LIMIT_BURST) + printf("--limit-burst %u ", r->burst); +} + +struct iptables_match limit += { NULL, + "limit", + NETFILTER_VERSION, + sizeof(struct ipt_rateinfo), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_match(&limit); +} diff --git a/extensions/libipt_mac.c b/extensions/libipt_mac.c new file mode 100644 index 00000000..36d89692 --- /dev/null +++ b/extensions/libipt_mac.c @@ -0,0 +1,144 @@ +/* Shared library add-on to iptables to add MAC address support. */ +#include +#include +#include +#include +#include +#if defined(__GLIBC__) && __GLIBC__ == 2 +#include +#else +#include +#endif +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"MAC v%s options:\n" +" --mac-source [!] XX:XX:XX:XX:XX:XX\n" +" Match source MAC address\n" +"\n", NETFILTER_VERSION); +} + +static struct option opts[] = { + { "mac-source", 1, 0, '1' }, + {0} +}; + +/* Initialize the match. */ +static void +init(struct ipt_entry_match *m, unsigned int *nfcache) +{ + /* Can't cache this */ + *nfcache |= NFC_UNKNOWN; +} + +static void +parse_mac(const char *mac, struct ipt_mac_info *info) +{ + unsigned int i = 0; + + if (strlen(mac) != ETH_ALEN*3-1) + exit_error(PARAMETER_PROBLEM, "Bad mac address `%s'", mac); + + for (i = 0; i < ETH_ALEN; i++) { + long number; + char *end; + + number = strtol(mac + i*3, &end, 16); + + if (end == mac + i*3 + 2 + && number >= 0 + && number <= 255) + info->srcaddr[i] = number; + else + exit_error(PARAMETER_PROBLEM, + "Bad mac address `%s'", mac); + } +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + struct ipt_mac_info *macinfo = (struct ipt_mac_info *)(*match)->data; + + switch (c) { + case '1': + if (check_inverse(optarg, &invert)) + optind++; + parse_mac(argv[optind-1], macinfo); + if (invert) + macinfo->invert = 1; + *flags = 1; + break; + + default: + return 0; + } + + return 1; +} + +static void print_mac(unsigned char macaddress[ETH_ALEN], int invert) +{ + unsigned int i; + + printf("%s%02X", invert ? "!" : "", macaddress[0]); + for (i = 1; i < ETH_ALEN; i++) + printf(":%02X", macaddress[i]); + printf(" "); +} + +/* Final check; must have specified --mac. */ +static void final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, + "You must specify `--mac-source'"); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) +{ + printf("MAC "); + print_mac(((struct ipt_mac_info *)match->data)->srcaddr, + ((struct ipt_mac_info *)match->data)->invert); +} + +/* Saves the union ipt_matchinfo in parsable form to stdout. */ +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + printf("--mac "); + print_mac(((struct ipt_mac_info *)match->data)->srcaddr, + ((struct ipt_mac_info *)match->data)->invert); +} + +struct iptables_match mac += { NULL, + "mac", + NETFILTER_VERSION, + sizeof(struct ipt_mac_info), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_match(&mac); +} diff --git a/extensions/libipt_mark.c b/extensions/libipt_mark.c new file mode 100644 index 00000000..318cd94d --- /dev/null +++ b/extensions/libipt_mark.c @@ -0,0 +1,128 @@ +/* Shared library add-on to iptables to add NFMARK matching support. */ +#include +#include +#include +#include +#include + +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"MARK match v%s options:\n" +"[!] --mark value[/mask] Match nfmark value with optional mask\n" +"\n", +NETFILTER_VERSION); +} + +static struct option opts[] = { + { "mark", 1, 0, '1' }, + {0} +}; + +/* Initialize the match. */ +static void +init(struct ipt_entry_match *m, unsigned int *nfcache) +{ + /* Can't cache this. */ + *nfcache |= NFC_UNKNOWN; +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + struct ipt_mark_info *markinfo = (struct ipt_mark_info *)(*match)->data; + + switch (c) { + char *end; + case '1': + if (check_inverse(optarg, &invert)) + optind++; + markinfo->mark = strtoul(optarg, &end, 0); + if (*end == '/') { + markinfo->mask = strtoul(end+1, &end, 0); + } else + markinfo->mask = 0xffffffff; + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg); + if (invert) + markinfo->invert = 1; + *flags = 1; + break; + + default: + return 0; + } + return 1; +} + +static void +print_mark(unsigned long mark, unsigned long mask, int invert, int numeric) +{ + if (invert) + fputc('!', stdout); + + if(mask != 0xffffffff) + printf("0x%lx/0x%lx ", mark, mask); + else + printf("0x%lx ", mark); +} + +/* Final check; must have specified --mark. */ +static void +final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, + "MARK match: You must specify `--mark'"); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) +{ + printf("MARK match "); + print_mark(((struct ipt_mark_info *)match->data)->mark, + ((struct ipt_mark_info *)match->data)->mask, + ((struct ipt_mark_info *)match->data)->invert, numeric); +} + +/* Saves the union ipt_matchinfo in parsable form to stdout. */ +static void +save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + printf("--mark "); + print_mark(((struct ipt_mark_info *)match->data)->mark, + ((struct ipt_mark_info *)match->data)->mask, + ((struct ipt_mark_info *)match->data)->invert, 0); +} + +struct iptables_match mark += { NULL, + "mark", + NETFILTER_VERSION, + sizeof(struct ipt_mark_info), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_match(&mark); +} diff --git a/extensions/libipt_multiport.c b/extensions/libipt_multiport.c new file mode 100644 index 00000000..727f95fc --- /dev/null +++ b/extensions/libipt_multiport.c @@ -0,0 +1,262 @@ +/* Shared library add-on to iptables to add multiple TCP port support. */ +#include +#include +#include +#include +#include +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"multiport v%s options:\n" +" --source-ports port[,port,port...]\n" +" --sports ...\n" +" match source port(s)\n" +" --destination-ports port[,port,port...]\n" +" --dports ...\n" +" match destination port(s)\n" +" --ports port[,port,port]\n" +" match both source and destination port(s)\n", +NETFILTER_VERSION); +} + +static struct option opts[] = { + { "source-ports", 1, 0, '1' }, + { "sports", 1, 0, '1' }, /* synonym */ + { "destination-ports", 1, 0, '2' }, + { "dports", 1, 0, '2' }, /* synonym */ + { "ports", 1, 0, '3' }, + {0} +}; + +static int +service_to_port(const char *name, const char *proto) +{ + struct servent *service; + + if ((service = getservbyname(name, proto)) != NULL) + return ntohs((unsigned short) service->s_port); + + return -1; +} + +static u_int16_t +parse_port(const char *port, const char *proto) +{ + int portnum; + if ((portnum = string_to_number(port, 0, 65535)) != -1 || + (portnum = service_to_port(port, proto)) != -1) + return (u_int16_t)portnum; + + exit_error(PARAMETER_PROBLEM, + "invalid port/service `%s' specified", port); +} + +static unsigned int +parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto) +{ + char *buffer, *cp, *next; + unsigned int i; + + buffer = strdup(portstring); + if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed"); + + for (cp=buffer, i=0; cp && iip.proto == IPPROTO_TCP) + return "tcp"; + else if (entry->ip.proto == IPPROTO_UDP) + return "udp"; + else if (!entry->ip.proto) + exit_error(PARAMETER_PROBLEM, + "multiport needs `-p tcp' or `-p udp'"); + else + exit_error(PARAMETER_PROBLEM, + "multiport only works with TCP or UDP"); +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + const char *proto; + struct ipt_multiport *multiinfo + = (struct ipt_multiport *)(*match)->data; + + switch (c) { + case '1': + proto = check_proto(entry); + multiinfo->count = parse_multi_ports(argv[optind-1], + multiinfo->ports, proto); + multiinfo->flags = IPT_MULTIPORT_SOURCE; + *nfcache |= NFC_IP_SRC_PT; + break; + + case '2': + proto = check_proto(entry); + multiinfo->count = parse_multi_ports(argv[optind-1], + multiinfo->ports, proto); + multiinfo->flags = IPT_MULTIPORT_DESTINATION; + *nfcache |= NFC_IP_DST_PT; + break; + + case '3': + proto = check_proto(entry); + multiinfo->count = parse_multi_ports(argv[optind-1], + multiinfo->ports, proto); + multiinfo->flags = IPT_MULTIPORT_EITHER; + *nfcache |= NFC_IP_SRC_PT | NFC_IP_DST_PT; + break; + + default: + return 0; + } + + if (*flags) + exit_error(PARAMETER_PROBLEM, + "multiport can only have one option"); + *flags = 1; + return 1; +} + +/* Final check; must specify something. */ +static void +final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, "multiport expection an option"); +} + +static char * +port_to_service(int port, u_int8_t proto) +{ + struct servent *service; + + if ((service = getservbyport(htons(port), + proto == IPPROTO_TCP ? "tcp" : "udp"))) + return service->s_name; + + return NULL; +} + +static void +print_port(u_int16_t port, u_int8_t protocol, int numeric) +{ + char *service; + + if (numeric || (service = port_to_service(port, protocol)) == NULL) + printf("%u", port); + else + printf("%s", service); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) +{ + const struct ipt_multiport *multiinfo + = (const struct ipt_multiport *)match->data; + unsigned int i; + + printf("multiport "); + + switch (multiinfo->flags) { + case IPT_MULTIPORT_SOURCE: + printf("sports "); + break; + + case IPT_MULTIPORT_DESTINATION: + printf("dports "); + break; + + case IPT_MULTIPORT_EITHER: + printf("ports "); + break; + + default: + printf("ERROR "); + break; + } + + for (i=0; i < multiinfo->count; i++) { + printf("%s", i ? "," : ""); + print_port(multiinfo->ports[i], ip->proto, numeric); + } + printf(" "); +} + +/* Saves the union ipt_matchinfo in parsable form to stdout. */ +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + const struct ipt_multiport *multiinfo + = (const struct ipt_multiport *)match->data; + unsigned int i; + + switch (multiinfo->flags) { + case IPT_MULTIPORT_SOURCE: + printf("--sports "); + break; + + case IPT_MULTIPORT_DESTINATION: + printf("--dports "); + break; + + case IPT_MULTIPORT_EITHER: + printf("--ports "); + break; + } + + for (i=0; i < multiinfo->count; i++) { + printf("%s", i ? "," : ""); + print_port(multiinfo->ports[i], ip->proto, 0); + } + printf(" "); +} + +struct iptables_match multiport += { NULL, + "multiport", + NETFILTER_VERSION, + sizeof(struct ipt_multiport), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void +_init(void) +{ + register_match(&multiport); +} diff --git a/extensions/libipt_owner.c b/extensions/libipt_owner.c new file mode 100644 index 00000000..29311022 --- /dev/null +++ b/extensions/libipt_owner.c @@ -0,0 +1,219 @@ +/* Shared library add-on to iptables to add OWNER matching support. */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"OWNER match v%s options:\n" +"[!] --uid-owner userid Match local uid\n" +"[!] --gid-owner groupid Match local gid\n" +"[!] --pid-owner processid Match local pid\n" +"[!] --sid-owner sessionid Match local sid\n" +"\n", +NETFILTER_VERSION); +} + +static struct option opts[] = { + { "uid-owner", 1, 0, '1' }, + { "gid-owner", 1, 0, '2' }, + { "pid-owner", 1, 0, '3' }, + { "sid-owner", 1, 0, '4' }, + {0} +}; + +/* Initialize the match. */ +static void +init(struct ipt_entry_match *m, unsigned int *nfcache) +{ + /* Can't cache this. */ + *nfcache |= NFC_UNKNOWN; +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + struct ipt_owner_info *ownerinfo = (struct ipt_owner_info *)(*match)->data; + + switch (c) { + char *end; + struct passwd *pwd; + struct group *grp; + case '1': + if (check_inverse(optarg, &invert)) + optind++; + + if ((pwd = getpwnam(optarg))) + ownerinfo->uid = pwd->pw_uid; + else { + ownerinfo->uid = strtoul(optarg, &end, 0); + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad OWNER UID value `%s'", optarg); + } + if (invert) + ownerinfo->invert |= IPT_OWNER_UID; + ownerinfo->match |= IPT_OWNER_UID; + *flags = 1; + break; + + case '2': + if (check_inverse(optarg, &invert)) + optind++; + if ((grp = getgrnam(optarg))) + ownerinfo->gid = grp->gr_gid; + else { + ownerinfo->gid = strtoul(optarg, &end, 0); + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad OWNER GID value `%s'", optarg); + } + if (invert) + ownerinfo->invert |= IPT_OWNER_GID; + ownerinfo->match |= IPT_OWNER_GID; + *flags = 1; + break; + + case '3': + if (check_inverse(optarg, &invert)) + optind++; + ownerinfo->pid = strtoul(optarg, &end, 0); + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad OWNER PID value `%s'", optarg); + if (invert) + ownerinfo->invert |= IPT_OWNER_PID; + ownerinfo->match |= IPT_OWNER_PID; + *flags = 1; + break; + + case '4': + if (check_inverse(optarg, &invert)) + optind++; + ownerinfo->sid = strtoul(optarg, &end, 0); + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad OWNER SID value `%s'", optarg); + if (invert) + ownerinfo->invert |= IPT_OWNER_SID; + ownerinfo->match |= IPT_OWNER_SID; + *flags = 1; + break; + + default: + return 0; + } + return 1; +} + +static void +print_item(struct ipt_owner_info *info, u_int8_t flag, int numeric, char *label) +{ + if(info->match & flag) { + + printf(label); + + if (info->invert & flag) + fputc('!', stdout); + + switch(info->match & flag) { + case IPT_OWNER_UID: + if(!numeric) { + struct passwd *pwd = getpwuid(info->uid); + + if(pwd && pwd->pw_name) { + printf("%s ", pwd->pw_name); + break; + } + /* FALLTHROUGH */ + } + printf("%u ", info->uid); + break; + case IPT_OWNER_GID: + if(!numeric) { + struct group *grp = getgrgid(info->gid); + + if(grp && grp->gr_name) { + printf("%s ", grp->gr_name); + break; + } + /* FALLTHROUGH */ + } + printf("%u ", info->gid); + break; + case IPT_OWNER_PID: + printf("%u ", info->pid); + break; + case IPT_OWNER_SID: + printf("%u ", info->sid); + break; + default: + break; + } + } +} + +/* Final check; must have specified --own. */ +static void +final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, + "OWNER match: You must specify one or more options"); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) +{ + struct ipt_owner_info *info = (struct ipt_owner_info *)match->data; + + print_item(info, IPT_OWNER_UID, numeric, "OWNER UID match "); + print_item(info, IPT_OWNER_GID, numeric, "OWNER GID match "); + print_item(info, IPT_OWNER_PID, numeric, "OWNER PID match "); + print_item(info, IPT_OWNER_SID, numeric, "OWNER SID match "); +} + +/* Saves the union ipt_matchinfo in parsable form to stdout. */ +static void +save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + struct ipt_owner_info *info = (struct ipt_owner_info *)match->data; + + print_item(info, IPT_OWNER_UID, 0, "--uid-owner "); + print_item(info, IPT_OWNER_GID, 0, "--gid-owner "); + print_item(info, IPT_OWNER_PID, 0, "--pid-owner "); + print_item(info, IPT_OWNER_SID, 0, "--sid-owner "); +} + +struct iptables_match owner += { NULL, + "owner", + NETFILTER_VERSION, + sizeof(struct ipt_owner_info), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_match(&owner); +} diff --git a/extensions/libipt_standard.c b/extensions/libipt_standard.c new file mode 100644 index 00000000..9a746b2d --- /dev/null +++ b/extensions/libipt_standard.c @@ -0,0 +1,67 @@ +/* Shared library add-on to iptables for standard target support. */ +#include +#include +#include +#include +#include +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"Standard v%s options:\n" +"(If target is DROP, ACCEPT, RETURN or nothing)\n", NETFILTER_VERSION); +} + +static struct option opts[] = { + {0} +}; + +/* Initialize the target. */ +static void +init(struct ipt_entry_target *t, unsigned int *nfcache) +{ +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + struct ipt_entry_target **target) +{ + return 0; +} + +/* Final check; don't care. */ +static void final_check(unsigned int flags) +{ +} + +/* Saves the targinfo in parsable form to stdout. */ +static void +save(const struct ipt_ip *ip, const struct ipt_entry_target *target) +{ +} + +struct iptables_target standard += { NULL, + "standard", + NETFILTER_VERSION, + sizeof(int), + &help, + &init, + &parse, + &final_check, + NULL, /* print */ + &save, + opts +}; + +void _init(void) +{ + register_target(&standard); +} diff --git a/extensions/libipt_state.c b/extensions/libipt_state.c new file mode 100644 index 00000000..19751d72 --- /dev/null +++ b/extensions/libipt_state.c @@ -0,0 +1,162 @@ +/* Shared library add-on to iptables to add state tracking support. */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"state v%s options:\n" +" [!] --state [INVALID|ESTABLISHED|NEW|RELATED][,...]\n" +" State(s) to match\n" +"\n", NETFILTER_VERSION); +} + +static struct option opts[] = { + { "state", 1, 0, '1' }, + {0} +}; + +/* Initialize the match. */ +static void +init(struct ipt_entry_match *m, unsigned int *nfcache) +{ + /* Can't cache this */ + *nfcache |= NFC_UNKNOWN; +} + +static int +parse_state(const char *state, size_t strlen, struct ipt_state_info *sinfo) +{ + if (strncasecmp(state, "INVALID", strlen) == 0) + sinfo->statemask |= IPT_STATE_INVALID; + else if (strncasecmp(state, "NEW", strlen) == 0) + sinfo->statemask |= IPT_STATE_BIT(IP_CT_NEW); + else if (strncasecmp(state, "ESTABLISHED", strlen) == 0) + sinfo->statemask |= IPT_STATE_BIT(IP_CT_ESTABLISHED); + else if (strncasecmp(state, "RELATED", strlen) == 0) + sinfo->statemask |= IPT_STATE_BIT(IP_CT_RELATED); + else + return 0; + return 1; +} + +static void +parse_states(const char *arg, struct ipt_state_info *sinfo) +{ + const char *comma; + + while ((comma = strchr(arg, ',')) != NULL) { + if (comma == arg || !parse_state(arg, comma-arg, sinfo)) + exit_error(PARAMETER_PROBLEM, "Bad state `%s'", arg); + arg = comma+1; + } + + if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo)) + exit_error(PARAMETER_PROBLEM, "Bad state `%s'", arg); +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + struct ipt_state_info *sinfo = (struct ipt_state_info *)(*match)->data; + + switch (c) { + case '1': + if (check_inverse(optarg, &invert)) + optind++; + + parse_states(argv[optind-1], sinfo); + if (invert) + sinfo->statemask = ~sinfo->statemask; + *flags = 1; + break; + + default: + return 0; + } + + return 1; +} + +/* Final check; must have specified --state. */ +static void final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, "You must specify `--state'"); +} + +static void print_state(unsigned int statemask) +{ + const char *sep = ""; + + if (statemask & IPT_STATE_INVALID) { + printf("%sINVALID", sep); + sep = ","; + } + if (statemask & IPT_STATE_BIT(IP_CT_NEW)) { + printf("%sNEW", sep); + sep = ","; + } + if (statemask & IPT_STATE_BIT(IP_CT_RELATED)) { + printf("%sRELATED", sep); + sep = ","; + } + if (statemask & IPT_STATE_BIT(IP_CT_ESTABLISHED)) { + printf("%sESTABLISHED", sep); + sep = ","; + } + printf(" "); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) +{ + struct ipt_state_info *sinfo = (struct ipt_state_info *)match->data; + + printf("state "); + print_state(sinfo->statemask); +} + +/* Saves the matchinfo in parsable form to stdout. */ +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + struct ipt_state_info *sinfo = (struct ipt_state_info *)match->data; + + printf("--state "); + print_state(sinfo->statemask); +} + +struct iptables_match state += { NULL, + "state", + NETFILTER_VERSION, + sizeof(struct ipt_state_info), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_match(&state); +} diff --git a/extensions/libipt_tcp.c b/extensions/libipt_tcp.c new file mode 100644 index 00000000..94285a09 --- /dev/null +++ b/extensions/libipt_tcp.c @@ -0,0 +1,439 @@ +/* Shared library add-on to iptables to add TCP support. */ +#include +#include +#include +#include +#include +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"TCP v%s options:\n" +" --tcp-flags [!] mask comp match when TCP flags & mask == comp\n" +" (Flags: SYN ACK FIN RST URG PSH ALL NONE)\n" +"[!] --syn match when only SYN flag set\n" +" (equivalent to --tcp-flags SYN,RST,ACK SYN)\n" +" --source-port [!] port[:port]\n" +" --sport ...\n" +" match source port(s)\n" +" --destination-port [!] port[:port]\n" +" --dport ...\n" +" match destination port(s)\n" +" --tcp-option [!] number match if TCP option set\n\n", +NETFILTER_VERSION); +} + +static struct option opts[] = { + { "source-port", 1, 0, '1' }, + { "sport", 1, 0, '1' }, /* synonym */ + { "destination-port", 1, 0, '2' }, + { "dport", 1, 0, '2' }, /* synonym */ + { "syn", 0, 0, '3' }, + { "tcp-flags", 1, 0, '4' }, + { "tcp-option", 1, 0, '5' }, + {0} +}; + +static int +service_to_port(const char *name) +{ + struct servent *service; + + if ((service = getservbyname(name, "tcp")) != NULL) + return ntohs((unsigned short) service->s_port); + + return -1; +} + +static u_int16_t +parse_tcp_port(const char *port) +{ + int portnum; + + if ((portnum = string_to_number(port, 0, 65535)) != -1 || + (portnum = service_to_port(port)) != -1) + return (u_int16_t)portnum; + + exit_error(PARAMETER_PROBLEM, + "invalid TCP port/service `%s' specified", port); +} + +static void +parse_tcp_ports(const char *portstring, u_int16_t *ports) +{ + char *buffer; + char *cp; + + buffer = strdup(portstring); + if ((cp = strchr(buffer, ':')) == NULL) + ports[0] = ports[1] = parse_tcp_port(buffer); + else { + *cp = '\0'; + cp++; + + ports[0] = buffer[0] ? parse_tcp_port(buffer) : 0; + ports[1] = cp[0] ? parse_tcp_port(cp) : 0xFFFF; + } + free(buffer); +} + +struct tcp_flag_names { + const char *name; + unsigned int flag; +}; + +static struct tcp_flag_names tcp_flag_names[] += { { "FIN", 0x01 }, + { "SYN", 0x02 }, + { "RST", 0x04 }, + { "PSH", 0x08 }, + { "ACK", 0x10 }, + { "URG", 0x20 }, + { "ALL", 0x3F }, + { "NONE", 0 }, +}; + +static unsigned int +parse_tcp_flag(const char *flags) +{ + unsigned int ret = 0; + char *ptr; + char *buffer; + + buffer = strdup(flags); + + for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) { + unsigned int i; + for (i = 0; + i < sizeof(tcp_flag_names)/sizeof(struct tcp_flag_names); + i++) { + if (strcasecmp(tcp_flag_names[i].name, ptr) == 0) { + ret |= tcp_flag_names[i].flag; + break; + } + } + if (i == sizeof(tcp_flag_names)/sizeof(struct tcp_flag_names)) + exit_error(PARAMETER_PROBLEM, + "Unknown TCP flag `%s'", buffer); + } + + free(buffer); + return ret; +} + +static void +parse_tcp_flags(struct ipt_tcp *tcpinfo, + const char *mask, + const char *cmp, + int invert) +{ + tcpinfo->flg_mask = parse_tcp_flag(mask); + tcpinfo->flg_cmp = parse_tcp_flag(cmp); + + if (invert) + tcpinfo->invflags |= IPT_TCP_INV_FLAGS; +} + +static void +parse_tcp_option(const char *option, u_int8_t *result) +{ + int ret; + + ret = string_to_number(option, 1, 255); + if (ret == -1) + exit_error(PARAMETER_PROBLEM, "Bad TCP option `%s'", option); + + *result = (u_int8_t)ret; +} + +/* Initialize the match. */ +static void +init(struct ipt_entry_match *m, unsigned int *nfcache) +{ + struct ipt_tcp *tcpinfo = (struct ipt_tcp *)m->data; + + tcpinfo->spts[1] = tcpinfo->dpts[1] = 0xFFFF; +} + +#define TCP_SRC_PORTS 0x01 +#define TCP_DST_PORTS 0x02 +#define TCP_FLAGS 0x04 +#define TCP_OPTION 0x08 + +/* Function which parses command options; returns true if it + ate an option. */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + struct ipt_tcp *tcpinfo = (struct ipt_tcp *)(*match)->data; + + switch (c) { + case '1': + if (*flags & TCP_SRC_PORTS) + exit_error(PARAMETER_PROBLEM, + "Only one `--source-port' allowed"); + if (check_inverse(optarg, &invert)) + optind++; + parse_tcp_ports(argv[optind-1], tcpinfo->spts); + if (invert) + tcpinfo->invflags |= IPT_TCP_INV_SRCPT; + *flags |= TCP_SRC_PORTS; + *nfcache |= NFC_IP_SRC_PT; + break; + + case '2': + if (*flags & TCP_DST_PORTS) + exit_error(PARAMETER_PROBLEM, + "Only one `--destination-port' allowed"); + if (check_inverse(optarg, &invert)) + optind++; + parse_tcp_ports(argv[optind-1], tcpinfo->dpts); + if (invert) + tcpinfo->invflags |= IPT_TCP_INV_DSTPT; + *flags |= TCP_DST_PORTS; + *nfcache |= NFC_IP_DST_PT; + break; + + case '3': + if (*flags & TCP_FLAGS) + exit_error(PARAMETER_PROBLEM, + "Only one of `--syn' or `--tcp-flags' " + " allowed"); + parse_tcp_flags(tcpinfo, "SYN,RST,ACK", "SYN", invert); + *flags |= TCP_FLAGS; + *nfcache |= NFC_IP_TCPFLAGS; + break; + + case '4': + if (*flags & TCP_FLAGS) + exit_error(PARAMETER_PROBLEM, + "Only one of `--syn' or `--tcp-flags' " + " allowed"); + if (check_inverse(optarg, &invert)) + optind++; + + if (!argv[optind] + || argv[optind][0] == '-' || argv[optind][0] == '!') + exit_error(PARAMETER_PROBLEM, + "--tcp-flags requires two args."); + + parse_tcp_flags(tcpinfo, optarg, argv[optind++], invert); + *flags |= TCP_FLAGS; + *nfcache |= NFC_IP_TCPFLAGS; + break; + + case '5': + if (*flags & TCP_OPTION) + exit_error(PARAMETER_PROBLEM, + "Only one `--tcp-option' allowed"); + if (check_inverse(optarg, &invert)) + optind++; + parse_tcp_option(argv[optind-1], &tcpinfo->option); + if (invert) + tcpinfo->invflags |= IPT_TCP_INV_OPTION; + *flags |= TCP_OPTION; + *nfcache |= NFC_IP_PROTO_UNKNOWN; + break; + + default: + return 0; + } + + return 1; +} + +/* Final check; we don't care. */ +static void +final_check(unsigned int flags) +{ +} + +static char * +port_to_service(int port) +{ + struct servent *service; + + if ((service = getservbyport(htons(port), "tcp"))) + return service->s_name; + + return NULL; +} + +static void +print_port(u_int16_t port, int numeric) +{ + char *service; + + if (numeric || (service = port_to_service(port)) == NULL) + printf("%u", port); + else + printf("%s", service); +} + +static void +print_ports(const char *name, u_int16_t min, u_int16_t max, + int invert, int numeric) +{ + const char *inv = invert ? "!" : ""; + + if (min != 0 || max != 0xFFFF || invert) { + printf("%s", name); + if (min == max) { + printf(":%s", inv); + print_port(min, numeric); + } else { + printf("s:%s", inv); + print_port(min, numeric); + printf(":"); + print_port(max, numeric); + } + printf(" "); + } +} + +static void +print_option(u_int8_t option, int invert, int numeric) +{ + if (option || invert) + printf("option=%s%u ", invert ? "!" : "", option); +} + +static void +print_tcpf(u_int8_t flags) +{ + int sole_flag = 1; + + do { + unsigned int i; + + /* Terminates because last flag is 0 */ + for (i = 0; !(flags & tcp_flag_names[i].flag); i++); + + if (!sole_flag) + printf(","); + printf("%s", tcp_flag_names[i].name); + sole_flag = 0; + + flags &= ~tcp_flag_names[i].flag; + } while (flags); +} + +static void +print_flags(u_int8_t mask, u_int8_t cmp, int invert, int numeric) +{ + if (mask || invert) { + printf("flags:%s", invert ? "!" : ""); + if (numeric) + printf("0x02%X/0x02%X ", mask, cmp); + else { + print_tcpf(cmp); + printf("/"); + print_tcpf(mask); + printf(" "); + } + } +} + +/* Prints out the union ipt_matchinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, int numeric) +{ + const struct ipt_tcp *tcp = (struct ipt_tcp *)match->data; + + printf("tcp "); + print_ports("spt", tcp->spts[0], tcp->spts[1], + tcp->invflags & IPT_TCP_INV_SRCPT, + numeric); + print_ports("dpt", tcp->dpts[0], tcp->dpts[1], + tcp->invflags & IPT_TCP_INV_DSTPT, + numeric); + print_option(tcp->option, + tcp->invflags & IPT_TCP_INV_OPTION, + numeric); + print_flags(tcp->flg_mask, tcp->flg_cmp, + tcp->invflags & IPT_TCP_INV_FLAGS, + numeric); + if (tcp->invflags & ~IPT_TCP_INV_MASK) + printf("Unknown invflags: 0x%X ", + tcp->invflags & ~IPT_TCP_INV_MASK); +} + +/* Saves the union ipt_matchinfo in parsable form to stdout. */ +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + const struct ipt_tcp *tcpinfo = (struct ipt_tcp *)match->data; + + if (tcpinfo->spts[0] != 0 + && tcpinfo->spts[1] != 0xFFFF) { + if (tcpinfo->invflags & IPT_TCP_INV_SRCPT) + printf("! "); + if (tcpinfo->spts[0] + != tcpinfo->spts[1]) + printf("--sport %u-%u ", + ntohs(tcpinfo->spts[0]), + ntohs(tcpinfo->spts[1])); + else + printf("--sport %u ", + ntohs(tcpinfo->spts[0])); + } + + if (tcpinfo->dpts[0] != 0 + && tcpinfo->dpts[1] != 0xFFFF) { + if (tcpinfo->invflags & IPT_TCP_INV_DSTPT) + printf("! "); + if (tcpinfo->dpts[0] + != tcpinfo->dpts[1]) + printf("--dport %u-%u ", + ntohs(tcpinfo->dpts[0]), + ntohs(tcpinfo->dpts[1])); + else + printf("--dport %u ", + ntohs(tcpinfo->dpts[0])); + } + + if (tcpinfo->option + || (tcpinfo->invflags & IPT_TCP_INV_OPTION)) { + if (tcpinfo->invflags & IPT_TCP_INV_OPTION) + printf("! "); + printf("--tcp-option %u ", tcpinfo->option); + } + + if (tcpinfo->flg_mask + || (tcpinfo->invflags & IPT_TCP_INV_FLAGS)) { + if (tcpinfo->invflags & IPT_TCP_INV_FLAGS) + printf("! "); + + print_tcpf(tcpinfo->flg_cmp); + if (tcpinfo->flg_mask != 0xFF) { + printf("/"); + print_tcpf(tcpinfo->flg_mask); + } + } +} + +struct iptables_match tcp += { NULL, + "tcp", + NETFILTER_VERSION, + sizeof(struct ipt_tcp), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts }; + +void +_init(void) +{ + register_match(&tcp); +} diff --git a/extensions/libipt_tos.c b/extensions/libipt_tos.c new file mode 100644 index 00000000..eb62081e --- /dev/null +++ b/extensions/libipt_tos.c @@ -0,0 +1,171 @@ +/* Shared library add-on to iptables to add TOS matching support. */ +#include +#include +#include +#include +#include + +#include +#include + +/* TOS names and values. */ +struct TOS_value +{ + unsigned char TOS; + const char *name; +} TOS_values[] = { + { IPTOS_LOWDELAY, "Minimize-Delay" }, + { IPTOS_THROUGHPUT, "Maximize-Throughput" }, + { IPTOS_RELIABILITY, "Maximize-Reliability" }, + { IPTOS_MINCOST, "Minimize-Cost" }, + { IPTOS_NORMALSVC, "Normal-Service" }, +}; + +/* Function which prints out usage message. */ +static void +help(void) +{ + unsigned int i; + + printf( +"TOS match v%s options:\n" +"[!] --tos value Match Type of Service field from one of the\n" +" following numeric or descriptive values:\n", +NETFILTER_VERSION); + + for (i = 0; i < sizeof(TOS_values)/sizeof(struct TOS_value);i++) + printf(" %s %u (0x%02x)\n", + TOS_values[i].name, + TOS_values[i].TOS, + TOS_values[i].TOS); + fputc('\n', stdout); +} + +static struct option opts[] = { + { "tos", 1, 0, '1' }, + {0} +}; + +/* Initialize the match. */ +static void +init(struct ipt_entry_match *m, unsigned int *nfcache) +{ + *nfcache |= NFC_IP_TOS; +} + +static void +parse_tos(const unsigned char *s, struct ipt_tos_info *info) +{ + unsigned int i; + int tos = string_to_number(s, 0, 255); + + if (tos != -1) { + if (tos == IPTOS_LOWDELAY + || tos == IPTOS_THROUGHPUT + || tos == IPTOS_RELIABILITY + || tos == IPTOS_MINCOST + || tos == IPTOS_NORMALSVC) { + info->tos = (u_int8_t )tos; + return; + } + } else { + for (i = 0; itos = TOS_values[i].TOS; + return; + } + } + exit_error(PARAMETER_PROBLEM, "Bad TOS value `%s'", s); +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + struct ipt_tos_info *tosinfo = (struct ipt_tos_info *)(*match)->data; + + switch (c) { + case '1': + if (check_inverse(optarg, &invert)) + optind++; + parse_tos(argv[optind-1], tosinfo); + if (invert) + tosinfo->invert = 1; + *flags = 1; + break; + + default: + return 0; + } + return 1; +} + +static void +print_tos(u_int8_t tos, int invert, int numeric) +{ + unsigned int i; + + if (invert) + fputc('!', stdout); + + if (!numeric) { + for (i = 0; idata)->tos, + ((struct ipt_tos_info *)match->data)->invert, numeric); +} + +/* Saves the union ipt_matchinfo in parsable form to stdout. */ +static void +save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + printf("--tos "); + print_tos(((struct ipt_tos_info *)match->data)->tos, + ((struct ipt_tos_info *)match->data)->invert, 0); +} + +struct iptables_match tos += { NULL, + "tos", + NETFILTER_VERSION, + sizeof(struct ipt_tos_info), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_match(&tos); +} diff --git a/extensions/libipt_udp.c b/extensions/libipt_udp.c new file mode 100644 index 00000000..e3593579 --- /dev/null +++ b/extensions/libipt_udp.c @@ -0,0 +1,252 @@ +/* Shared library add-on to iptables to add UDP support. */ +#include +#include +#include +#include +#include +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"UDP v%s options:\n" +" --source-port [!] port[:port]\n" +" --sport ...\n" +" match source port(s)\n" +" --destination-port [!] port[:port]\n" +" --dport ...\n" +" match destination port(s)\n", +NETFILTER_VERSION); +} + +static struct option opts[] = { + { "source-port", 1, 0, '1' }, + { "sport", 1, 0, '1' }, /* synonym */ + { "destination-port", 1, 0, '2' }, + { "dport", 1, 0, '2' }, /* synonym */ + {0} +}; + +static int +service_to_port(const char *name) +{ + struct servent *service; + + if ((service = getservbyname(name, "udp")) != NULL) + return ntohs((unsigned short) service->s_port); + + return -1; +} + +static u_int16_t +parse_udp_port(const char *port) +{ + int portnum; + + if ((portnum = string_to_number(port, 0, 65535)) != -1 || + (portnum = service_to_port(port)) != -1) + return (u_int16_t)portnum; + + exit_error(PARAMETER_PROBLEM, + "invalid UDP port/service `%s' specified", port); + } + +static void +parse_udp_ports(const char *portstring, u_int16_t *ports) +{ + char *buffer; + char *cp; + + buffer = strdup(portstring); + if ((cp = strchr(buffer, ':')) == NULL) + ports[0] = ports[1] = parse_udp_port(buffer); + else { + *cp = '\0'; + cp++; + + ports[0] = buffer[0] ? parse_udp_port(buffer) : 0; + ports[1] = cp[0] ? parse_udp_port(cp) : 0xFFFF; + } + free(buffer); +} + +/* Initialize the match. */ +static void +init(struct ipt_entry_match *m, unsigned int *nfcache) +{ + struct ipt_udp *udpinfo = (struct ipt_udp *)m->data; + + udpinfo->spts[1] = udpinfo->dpts[1] = 0xFFFF; +} + +#define UDP_SRC_PORTS 0x01 +#define UDP_DST_PORTS 0x02 + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + struct ipt_udp *udpinfo = (struct ipt_udp *)(*match)->data; + + switch (c) { + case '1': + if (*flags & UDP_SRC_PORTS) + exit_error(PARAMETER_PROBLEM, + "Only one `--source-port' allowed"); + if (check_inverse(optarg, &invert)) + optind++; + parse_udp_ports(argv[optind-1], udpinfo->spts); + if (invert) + udpinfo->invflags |= IPT_UDP_INV_SRCPT; + *flags |= UDP_SRC_PORTS; + *nfcache |= NFC_IP_SRC_PT; + break; + + case '2': + if (*flags & UDP_DST_PORTS) + exit_error(PARAMETER_PROBLEM, + "Only one `--destination-port' allowed"); + if (check_inverse(optarg, &invert)) + optind++; + parse_udp_ports(argv[optind-1], udpinfo->dpts); + if (invert) + udpinfo->invflags |= IPT_UDP_INV_DSTPT; + *flags |= UDP_DST_PORTS; + *nfcache |= NFC_IP_DST_PT; + break; + + default: + return 0; + } + + return 1; +} + +/* Final check; we don't care. */ +static void +final_check(unsigned int flags) +{ +} + +static char * +port_to_service(int port) +{ + struct servent *service; + + if ((service = getservbyport(htons(port), "udp"))) + return service->s_name; + + return NULL; +} + +static void +print_port(u_int16_t port, int numeric) +{ + char *service; + + if (numeric || (service = port_to_service(port)) == NULL) + printf("%u", port); + else + printf("%s", service); +} + +static void +print_ports(const char *name, u_int16_t min, u_int16_t max, + int invert, int numeric) +{ + const char *inv = invert ? "!" : ""; + + if (min != 0 || max != 0xFFFF || invert) { + printf("%s", name); + if (min == max) { + printf(":%s", inv); + print_port(min, numeric); + } else { + printf("s:%s", inv); + print_port(min, numeric); + printf(":"); + print_port(max, numeric); + } + printf(" "); + } +} + +/* Prints out the union ipt_matchinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, int numeric) +{ + const struct ipt_udp *udp = (struct ipt_udp *)match->data; + + printf("udp "); + print_ports("spt", udp->spts[0], udp->spts[1], + udp->invflags & IPT_UDP_INV_SRCPT, + numeric); + print_ports("dpt", udp->dpts[0], udp->dpts[1], + udp->invflags & IPT_UDP_INV_DSTPT, + numeric); + if (udp->invflags & ~IPT_UDP_INV_MASK) + printf("Unknown invflags: 0x%X ", + udp->invflags & ~IPT_UDP_INV_MASK); +} + +/* Saves the union ipt_matchinfo in parsable form to stdout. */ +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + const struct ipt_udp *udpinfo = (struct ipt_udp *)match->data; + + if (udpinfo->spts[0] != 0 + && udpinfo->spts[1] != 0xFFFF) { + if (udpinfo->invflags & IPT_UDP_INV_SRCPT) + printf("! "); + if (udpinfo->spts[0] + != udpinfo->spts[1]) + printf("--sport %u-%u ", + ntohs(udpinfo->spts[0]), + ntohs(udpinfo->spts[1])); + else + printf("--sport %u ", + ntohs(udpinfo->spts[0])); + } + + if (udpinfo->dpts[0] != 0 + && udpinfo->dpts[1] != 0xFFFF) { + if (udpinfo->invflags & IPT_UDP_INV_DSTPT) + printf("! "); + if (udpinfo->dpts[0] + != udpinfo->dpts[1]) + printf("--dport %u-%u ", + ntohs(udpinfo->dpts[0]), + ntohs(udpinfo->dpts[1])); + else + printf("--dport %u ", + ntohs(udpinfo->dpts[0])); + } +} + +struct iptables_match udp += { NULL, + "udp", + NETFILTER_VERSION, + sizeof(struct ipt_udp), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void +_init(void) +{ + register_match(&udp); +} diff --git a/extensions/libipt_unclean.c b/extensions/libipt_unclean.c new file mode 100644 index 00000000..50f62bdc --- /dev/null +++ b/extensions/libipt_unclean.c @@ -0,0 +1,66 @@ +/* Shared library add-on to iptables for unclean. */ +#include +#include +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"unclean v%s takes no options\n" +"\n", NETFILTER_VERSION); +} + +static struct option opts[] = { + {0} +}; + +/* Initialize the match. */ +static void +init(struct ipt_entry_match *m, unsigned int *nfcache) +{ + /* Can't cache this. */ + *nfcache |= NFC_UNKNOWN; +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + return 0; +} + +/* Final check; must have specified --mac. */ +static void final_check(unsigned int flags) +{ +} + +/* Saves the union ipt_matchinfo in parsable form to stdout. */ +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ +} + +struct iptables_match unclean += { NULL, + "unclean", + NETFILTER_VERSION, + 0, + &help, + &init, + &parse, + &final_check, + NULL, /* print */ + &save, + opts +}; + +void _init(void) +{ + register_match(&unclean); +} -- cgit v1.2.3