ROUTE target for IPv6
PATCH 1/1 ROUTE target for IPv6
Hi all,
Here is a port of the ROUTE target for IPv6. It is based on the IPv4 version of the ROUTE target. It has the same behaviour although not all options are currently implemented.
Current options are
--oif ifname Route the packet through `ifname' network interface --gw ip Route the packet via this gateway --continue Route the packet and continue traversing the rules.
This target is not working as a module since rt6_lookup is not exported.
The patch is against current CVS.
Cedric
patch-o-matic/extra/ROUTE.patch.ipv6 +319 -0
@@ -0,0 +1,319 @@ +diff -Nru linux.orig/include/linux/netfilter_ipv6/ip6t_ROUTE.h linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h +--- linux.orig/include/linux/netfilter_ipv6/ip6t_ROUTE.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h 2003-08-05 16:41:43.000000000 +0200 +@@ -0,0 +1,22 @@ ++/* Header file for iptables ip6t_ROUTE target ++ * ++ * (C) 2003 by Cédric de Launois <[email protected]> ++ * ++ * This software is distributed under GNU GPL v2, 1991 ++ */ ++#ifndef _IPT_ROUTE_H_target ++#define _IPT_ROUTE_H_target ++ ++#define IP6T_ROUTE_IFNAMSIZ 16 ++ ++struct ip6t_route_target_info { ++ char oif[IP6T_ROUTE_IFNAMSIZ]; /* Output Interface Name */ ++ char iif[IP6T_ROUTE_IFNAMSIZ]; /* Input Interface Name */ ++ u_int32_t gw[4]; /* IPv6 address of gateway */ ++ u_int8_t flags; ++}; ++ ++/* Values for "flags" field */ ++#define IP6T_ROUTE_CONTINUE 0x01 ++ ++#endif /*_IP6T_ROUTE_H_target*/ +diff -Nru linux.orig/net/ipv6/netfilter/ip6t_ROUTE.c linux/net/ipv6/netfilter/ip6t_ROUTE.c +--- linux.orig/net/ipv6/netfilter/ip6t_ROUTE.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/ipv6/netfilter/ip6t_ROUTE.c 2003-08-28 11:32:49.000000000 +0200 +@@ -0,0 +1,289 @@ ++/* ++ * This implements the ROUTE v6 target, which enables you to setup unusual ++ * routes not supported by the standard kernel routing table. ++ * ++ * Copyright (C) 2003 Cedric de Launois <[email protected]> ++ * ++ * v 1.0 2003/08/05 ++ * ++ * This software is distributed under GNU GPL v2, 1991 ++ */ ++ ++#include <linux/module.h> ++#include <linux/skbuff.h> ++#include <linux/ipv6.h> ++#include <linux/netfilter_ipv6/ip6_tables.h> ++#include <linux/netfilter_ipv6/ip6t_ROUTE.h> ++#include <linux/netdevice.h> ++#include <net/ipv6.h> ++#include <net/ndisc.h> ++#include <net/ip6_route.h> ++#include <linux/icmpv6.h> ++ ++#if 1 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++#define NIP6(addr) \ ++ ntohs((addr).s6_addr16[0]), \ ++ ntohs((addr).s6_addr16[1]), \ ++ ntohs((addr).s6_addr16[2]), \ ++ ntohs((addr).s6_addr16[3]), \ ++ ntohs((addr).s6_addr16[4]), \ ++ ntohs((addr).s6_addr16[5]), \ ++ ntohs((addr).s6_addr16[6]), \ ++ ntohs((addr).s6_addr16[7]) ++ ++/* Route the packet according to the routing keys specified in ++ * route_info. Keys are : ++ * - ifindex : ++ * 0 if no oif preferred, ++ * otherwise set to the index of the desired oif ++ * - route_info->gw : ++ * 0 if no gateway specified, ++ * otherwise set to the next host to which the pkt must be routed ++ * If success, skb->dev is the output device to which the packet must ++ * be sent and skb->dst is not NULL ++ * ++ * RETURN: 1 if the packet was succesfully routed to the ++ * destination desired ++ * 0 if the kernel routing table could not route the packet ++ * according to the keys specified ++ */ ++static int ++route6(struct sk_buff *skb, ++ unsigned int ifindex, ++ const struct ip6t_route_target_info *route_info) ++{ ++ struct rt6_info *rt = NULL; ++ struct ipv6hdr *ipv6h = skb->nh.ipv6h; ++ struct in6_addr *gw = (struct in6_addr*)&route_info->gw; ++ ++ DEBUGP("ip6t_ROUTE: called with: "); ++ DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr)); ++ DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw)); ++ DEBUGP("OUT=%s\n", route_info->oif); ++ ++ if (ipv6_addr_any(gw)) ++ rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1); ++ else ++ rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1); ++ ++ if (!rt) ++ goto no_route; ++ ++ DEBUGP("ip6t_ROUTE: routing gives: "); ++ DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr)); ++ DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway)); ++ DEBUGP("OUT=%s\n", rt->rt6i_dev->name); ++ ++ if (ifindex && rt->rt6i_dev->ifindex!=ifindex) ++ goto wrong_route; ++ ++ if (!rt->rt6i_nexthop) { ++ DEBUGP("ip6t_ROUTE: discovering neighbour\n"); ++ rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr); ++ } ++ ++ /* Drop old route. */ ++ dst_release(skb->dst); ++ skb->dst = &rt->u.dst; ++ skb->dev = rt->rt6i_dev; ++ return 1; ++ ++ wrong_route: ++ dst_release(&rt->u.dst); ++ no_route: ++ if (!net_ratelimit()) ++ return 0; ++ ++ printk("ip6t_ROUTE: no explicit route found "); ++ if (ifindex) ++ printk("via interface %s ", route_info->oif); ++ if (!ipv6_addr_any(gw)) ++ printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw)); ++ printk("\n"); ++ return 0; ++} ++ ++ ++/* Stolen from ip6_output_finish ++ * PRE : skb->dev is set to the device we are leaving by ++ * skb->dst is not NULL ++ * POST: the packet is sent with the link layer header pushed ++ * the packet is destroyed ++ */ ++static void ip_direct_send(struct sk_buff *skb) ++{ ++ struct dst_entry *dst = skb->dst; ++ struct hh_cache *hh = dst->hh; ++ ++ if (hh) { ++ read_lock_bh(&hh->hh_lock); ++ memcpy(skb->data - 16, hh->hh_data, 16); ++ read_unlock_bh(&hh->hh_lock); ++ skb_push(skb, hh->hh_len); ++ hh->hh_output(skb); ++ } else if (dst->neighbour) ++ dst->neighbour->output(skb); ++ else { ++ if (net_ratelimit()) ++ DEBUGP(KERN_DEBUG "ip6t_ROUTE: no hdr & no neighbour cache!\n"); ++ kfree_skb(skb); ++ } ++} ++ ++ ++static unsigned int ++route6_oif(const struct ip6t_route_target_info *route_info, ++ struct sk_buff *skb) ++{ ++ unsigned int ifindex = 0; ++ struct net_device *dev_out = NULL; ++ ++ /* The user set the interface name to use. ++ * Getting the current interface index. ++ */ ++ if ((dev_out = dev_get_by_name(route_info->oif))) { ++ ifindex = dev_out->ifindex; ++ } else { ++ /* Unknown interface name : packet dropped */ ++ if (net_ratelimit()) ++ DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif); ++ ++ if (route_info->flags & IP6T_ROUTE_CONTINUE) ++ return IP6T_CONTINUE; ++ else ++ return NF_DROP; ++ } ++ ++ /* Trying the standard way of routing packets */ ++ if (route6(skb, ifindex, route_info)) { ++ dev_put(dev_out); ++ if (route_info->flags & IP6T_ROUTE_CONTINUE) ++ return IP6T_CONTINUE; ++ ++ ip_direct_send(skb); ++ return NF_STOLEN; ++ } else ++ return NF_DROP; ++} ++ ++ ++static unsigned int ++route6_gw(const struct ip6t_route_target_info *route_info, ++ struct sk_buff *skb) ++{ ++ if (route6(skb, 0, route_info)) { ++ if (route_info->flags & IP6T_ROUTE_CONTINUE) ++ return IP6T_CONTINUE; ++ ++ ip_direct_send(skb); ++ return NF_STOLEN; ++ } else ++ return NF_DROP; ++} ++ ++ ++static unsigned int ++ip6t_route_target(struct sk_buff **pskb, ++ unsigned int hooknum, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *targinfo, ++ void *userinfo) ++{ ++ const struct ip6t_route_target_info *route_info = targinfo; ++ struct sk_buff *skb = *pskb; ++ struct in6_addr *gw = (struct in6_addr*)&route_info->gw; ++ ++ if (route_info->flags & IP6T_ROUTE_CONTINUE) ++ goto do_it; ++ ++ /* If we are at PREROUTING or INPUT hook ++ * the TTL isn't decreased by the IP stack ++ */ ++ if (hooknum == NF_IP6_PRE_ROUTING || ++ hooknum == NF_IP6_LOCAL_IN) { ++ ++ struct ipv6hdr *ipv6h = skb->nh.ipv6h; ++ ++ if (ipv6h->hop_limit <= 1) { ++ /* Force OUTPUT device used as source address */ ++ skb->dev = skb->dst->dev; ++ ++ icmpv6_send(skb, ICMPV6_TIME_EXCEED, ++ ICMPV6_EXC_HOPLIMIT, 0, skb->dev); ++ ++ return NF_DROP; ++ } ++ ++ ipv6h->hop_limit--; ++ } ++ ++ ++ do_it: ++ if (route_info->oif[0]) ++ return route6_oif(route_info, *pskb); ++ ++ if (!ipv6_addr_any(gw)) ++ return route6_gw(route_info, *pskb); ++ ++ if (net_ratelimit()) ++ DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n"); ++ ++ return IP6T_CONTINUE; ++} ++ ++ ++static int ++ip6t_route_checkentry(const char *tablename, ++ const struct ip6t_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ if (strcmp(tablename, "mangle") != 0) { ++ printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n"); ++ return 0; ++ } ++ ++ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) { ++ printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n", ++ targinfosize, ++ IP6T_ALIGN(sizeof(struct ip6t_route_target_info))); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++static struct ip6t_target ip6t_route_reg = { ++ .name = "ROUTE", ++ .target = ip6t_route_target, ++ .checkentry = ip6t_route_checkentry, ++ .me = THIS_MODULE ++}; ++ ++ ++static int __init init(void) ++{ ++ printk(KERN_DEBUG "registering ipv6 ROUTE target\n"); ++ if (ip6t_register_target(&ip6t_route_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++ ++static void __exit fini(void) ++{ ++ ip6t_unregister_target(&ip6t_route_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL");
patch-o-matic/extra/ROUTE.patch.ipv6.config.in +2 -0
@@ -0,0 +1,2 @@ + dep_tristate ' MARK target support' CONFIG_IP6_NF_TARGET_MARK $CONFIG_IP6_NF_MANGLE + dep_mbool ' ROUTE target support' CONFIG_IP6_NF_TARGET_ROUTE $CONFIG_IP6_NF_MANGLE
patch-o-matic/extra/ROUTE.patch.ipv6.configure.help +12 -0
@@ -0,0 +1,12 @@ +CONFIG_IP6_NF_TARGET_MARK +ROUTE target support +CONFIG_IP6_NF_TARGET_ROUTE + This option adds a `ROUTE' target, which enables you to setup unusual + routes. The ROUTE target is also able to change the incoming interface + of a packet. + + The target can be or not a final target. It has to be used inside the + mangle table. + + Not working as a module. +
patch-o-matic/extra/ROUTE.patch.ipv6.help +28 -0
@@ -0,0 +1,28 @@ +Author: Cédric de Launois <[email protected]> +Status: Experimental + + This option adds a `ROUTE' target, which enables you to setup unusual + routes. The ROUTE target is also able to change the incoming interface + of a packet. + + The target can be or not a final target. It has to be used inside the + mangle table. + + ROUTE target options: + --oif ifname Send the packet out using `ifname' network interface. + --gw ip Route the packet via this gateway. + --continue Route the packet and continue traversing the rules. + + Examples : + + # To force all outgoing icmpv6 packet to go through the eth1 interface + # (final target) : + ip6tables -A POSTROUTING -t mangle -p icmpv6 -j ROUTE --oif eth1 + + # To tunnel outgoing http packets and continue traversing the rules : + ip6tables -A POSTROUTING -t mangle -p tcp --dport 80 -j ROUTE --oif tunl1 --continue + + # To forward all ssh packets to a gateway, and continue traversing + # the rules : + ip6tables -A POSTROUTING -t mangle -p tcp --dport 22 -j ROUTE --gw <ipv6_address> --continue +
patch-o-matic/extra/ROUTE.patch.ipv6.makefile +2 -0
@@ -0,0 +1,2 @@ +obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o +obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o
userspace/extensions/libip6t_ROUTE.c +209 -0
209 lines not on this page · raw message
userspace/extensions/.ROUTE-test6 +2 -0
@@ -0,0 +1,2 @@ +#! /bin/sh +[ -f $KERNEL_DIR/include/linux/netfilter_ipv6/ip6t_ROUTE.h ] && echo ROUTE
Harald Welte
AppliedQuoted 5 lines · Cedric de Launois
Hi all,
Here is a port of the ROUTE target for IPv6. It is based on the IPv4 version of the ROUTE target. It has the same behaviour although not all options are currently implemented.
thanks, applied.
Quoted 1 line
Cedric
Signature · 5 lines
- Harald Welte <[email protected]> http://www.netfilter.org/ ============================================================================ "Fragmentation is like classful addressing -- an interesting early architectural error that shows how much experimentation was going on while IP was being designed." -- Paul Vixie