From f1c29980a836057ca20d838d3b96a03872dfbad8 Mon Sep 17 00:00:00 2001 From: Brian Candler Date: Tue, 3 May 2011 21:44:02 +0100 Subject: [PATCH] Non-functioning experiment at iptables netfilter support --- lib/netlink/c_struct.rb | 2 ++ lib/netlink/constants.rb | 53 ++++++++++++++++++++++++++++ lib/netlink/iptables4.rb | 76 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 lib/netlink/iptables4.rb diff --git a/lib/netlink/c_struct.rb b/lib/netlink/c_struct.rb index a7cb594..d1ba3cc 100644 --- a/lib/netlink/c_struct.rb +++ b/lib/netlink/c_struct.rb @@ -65,9 +65,11 @@ class CStruct define_type :uchar, :pattern => "C" define_type :uint16, :pattern => "S", :align => true define_type :uint32, :pattern => "L", :align => true + define_type :uint64, :pattern => "Q", :align => true define_type :char, :pattern => "c" define_type :int16, :pattern => "s", :align => true define_type :int32, :pattern => "l", :align => true + define_type :int64, :pattern => "q", :align => true define_type :ushort, :pattern => "S_", :align => true define_type :uint, :pattern => "I", :align => true define_type :ulong, :pattern => "L_", :align => true diff --git a/lib/netlink/constants.rb b/lib/netlink/constants.rb index 72c606c..10197c3 100644 --- a/lib/netlink/constants.rb +++ b/lib/netlink/constants.rb @@ -3,6 +3,8 @@ class Socket # From bits/socket.h PF_NETLINK = 16 unless defined? Socket::PF_NETLINK AF_NETLINK = PF_NETLINK unless defined? Socket::AF_NETLINK + # From in.h + IPPROTO_IPV6 = 41 unless defined? Socket::IPPROTO_IPV6 end module Netlink @@ -327,6 +329,20 @@ module Netlink NF_REPEAT = 4 NF_STOP = 5 + NF_INET_PRE_ROUTING = 0 + NF_INET_LOCAL_IN = 1 + NF_INET_FORWARD = 2 + NF_INET_LOCAL_OUT = 3 + NF_INET_POST_ROUTING = 4 + NF_INET_NUMHOOKS = 5 + + NFPROTO_UNSPEC = 0 + NFPROTO_IPV4 = 2 + NFPROTO_ARP = 3 + NFPROTO_BRIDGE = 7 + NFPROTO_IPV6 = 10 + NFPROTO_DECNET = 12 + # linux/netfilter_ipv4/ip_queue.h IPQ_COPY_NONE = 0 IPQ_COPY_META = 1 @@ -340,4 +356,41 @@ module Netlink # linux/netfilter_ipv4/ipt_ULOG.h ULOG_MAC_LEN = 80 ULOG_PREFIX_LEN = 32 + + # linux/netfilter/x_tables.h + XT_TABLE_MAXNAMELEN = 32 + + XT_CONTINUE = 0xffffffff + XT_RETURN = (-NF_REPEAT - 1) + + XT_INV_PROTO = 0x40 + + # linux/netfilter_ipv4/ip_tables.h + IPT_TABLE_MAXNAMELEN = XT_TABLE_MAXNAMELEN + + IPT_F_FRAG = 0x01 + IPT_F_GOTO = 0x02 + IPT_F_MASK = 0x03 + + IPT_INV_VIA_IN = 0x01 + IPT_INV_VIA_OUT = 0x02 + IPT_INV_TOS = 0x04 + IPT_INV_SRCIP = 0x08 + IPT_INV_DSTIP = 0x10 + IPT_INV_FRAG = 0x20 + IPT_INV_PROTO = XT_INV_PROTO + IPT_INV_MASK = 0x7f + + IPT_BASE_CTL = 64 + + IPT_SO_SET_REPLACE = IPT_BASE_CTL + IPT_SO_SET_ADD_COUNTERS = IPT_BASE_CTL + 1 + + IPT_SO_GET_INFO = IPT_BASE_CTL + IPT_SO_GET_ENTRIES = IPT_BASE_CTL + 1 + IPT_SO_GET_REVISION_MATCH = IPT_BASE_CTL + 2 + IPT_SO_GET_REVISION_TARGET = IPT_BASE_CTL + 3 + + IPT_CONTINUE = XT_CONTINUE + IPT_RETURN = XT_RETURN end diff --git a/lib/netlink/iptables4.rb b/lib/netlink/iptables4.rb new file mode 100644 index 0000000..475e2bc --- /dev/null +++ b/lib/netlink/iptables4.rb @@ -0,0 +1,76 @@ +require 'socket' +require 'netlink/c_struct' +require 'netlink/message' # just for :dev_name type +require 'netlink/constants' + +module Netlink + #- + # Definitions mainly from linux/netfilter_ipv4/ip_tables.h + #+ + + # struct ipt_getinfo + class IPTGetInfo < CStruct + field :name, :pattern=>"Z#{IPT_TABLE_MAXNAMELEN}", :default=>EMPTY_STRING + field :valid_hooks, :int + #field :hook_entry, :pattern=>"I#{NF_INET_NUMHOOKS}", :default=>[0]*NF_INET_NUMHOOKS + #field :underflow, :pattern=>"I#{NF_INET_NUMHOOKS}", :default=>[0]*NF_INET_NUMHOOKS + field :hook_entry, :pattern=>"a#{NF_INET_NUMHOOKS*4}", :default=>EMPTY_STRING + field :underflow, :pattern=>"a#{NF_INET_NUMHOOKS*4}", :default=>EMPTY_STRING + field :num_entries, :int + field :size, :int + end + + # struct ipt_get_entries + class IPTGetEntries < CStruct + field :name, :pattern=>"Z#{IPT_TABLE_MAXNAMELEN}", :default=>EMPTY_STRING + field :size, :uint + #field :entrytable, :pattern=> + field :entrytable, :binary # struct ipt_entry entrytable[] + end + + # struct ipt_entry + class IPTEntry < CStruct + #### struct ipt_ip + field :src, :nl # struct in_addr + field :dst, :nl + field :smsk, :nl + field :dmsk, :nl + field :iniface, :dev_name + field :outiface, :dev_name + field :iniface_mask, :dev_name + field :outiface_mask, :dev_name + field :proto, :uint16 + field :flags, :uchar + field :invflags, :uchar + #### + field :nfcache, :int + field :target_offset, :uint16 + field :next_offset, :uint16 + field :comefrom, :uint + field :packet_count, :uint64 + field :byte_count, :uint64 + field :elems, :binary + end + + # Class for handling iptables. Note that this doesn't actually use + # Netlink at all :-( + class Iptables4 + TC_AF = Socket::AF_INET + TC_IPPROTO = Socket::IPPROTO_IP + SO_GET_INFO = IPT_SO_GET_INFO + STRUCT_GETINFO = IPTGetInfo + STRUCT_GET_ENTRIES = IPTGetEntries + + def initialize(tablename = "filter") + @socket = Socket.new(TC_AF, Socket::SOCK_RAW, Socket::IPPROTO_RAW) + info = STRUCT_GETINFO.new(:name => tablename) + # FIXME: ruby won't let us pass structure to getsockopt!! + @socket.getsockopt(TC_IPPROTO, SO_GET_INFO, info) + warn "valid_hooks=0x%08x, num_entries=%d, size=%d" % [info.valid_hooks, info.size, info.num_entries] + end + end +end + +if __FILE__ == $0 + iptables = Netlink::Iptables4.new +end