Add NETFILTER_NFLOG (ULOG) support

This commit is contained in:
Brian Candler
2011-05-02 20:27:05 +01:00
parent a6eda43b2e
commit ddba99c3b3
6 changed files with 84 additions and 4 deletions

14
examples/nflog.rb Normal file
View File

@@ -0,0 +1,14 @@
LIBDIR = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
$LOAD_PATH.unshift LIBDIR
require 'pp'
require 'netlink/nflog'
# Example of using Netlink::NFLog to capture all outbound packets
# to TCP port 7551. Use "telnet 127.0.0.1 7551" to test.
#system("iptables -I OUTPUT -j ULOG --ulog-nlgroup 1 -p tcp --destination-port 7551")
nl = Netlink::NFLog::Socket.new(:group => 1)
nl.dequeue_packets do |pkt|
p pkt
end

View File

@@ -101,6 +101,11 @@ class CStruct
end
end
# This hook is called after unpacking from binary, and can be used
# for fixing up the data
def after_parse
end
def to_hash
@attrs
end
@@ -177,6 +182,7 @@ class CStruct
data.unpack(self::FORMAT).zip(self::FIELDS).each do |val, key|
obj[key] = val
end
obj.after_parse
obj
end

View File

@@ -309,4 +309,8 @@ module Netlink
IPQM_VERDICT = 18
IPQM_PACKET = 19
IPQM_MAX = 20
# linux/netfilter_ipv4/ipt_ULOG.h
ULOG_MAC_LEN = 80
ULOG_PREFIX_LEN = 32
end

View File

@@ -16,14 +16,18 @@ module Netlink
field :timestamp_sec, :long
field :timestamp_usec, :long
field :hook, :uint
field :indev_name, :pattern => "Z#{IFNAMSIZ}", :default => EMPTY_STRING
field :outdev_name, :pattern => "Z#{IFNAMSIZ}", :default => EMPTY_STRING
field :indev_name, :dev_name
field :outdev_name, :dev_name
field :hw_protocol, :ns
field :hw_type, :ushort
field :hw_addrlen, :uchar
field :hw_addr, :pattern => "a8", :default => EMPTY_STRING
field :data_len, :size_t
field :payload, :binary # TODO: clip to data_len
field :payload, :binary
def after_parse #:nodoc:
payload.slice!(data_len..-1) if payload.length > data_len
end
end
# struct ipq_verdict_msg

View File

@@ -18,11 +18,15 @@ module Netlink
# Use RtattrMessage instead for messages which are followed by variable rtattrs.
class Message < CStruct
# Map of numeric message type code => message class
# (TODO: should these be scoped to NETLINK_* protocol id?)
CODE_TO_MESSAGE = {}
# Define which message type code(s) to build using this structure
def self.code(*codes)
codes.each { |code| CODE_TO_MESSAGE[code] = self }
codes.each do |code|
warn "Duplicate message code: #{code}" if CODE_TO_MESSAGE[code]
CODE_TO_MESSAGE[code] = self
end
end
NLMSG_ALIGNTO_1 = NLMSG_ALIGNTO-1 #:nodoc:
@@ -51,6 +55,8 @@ module Netlink
# specify :pack and :unpack lambdas to do higher-level conversion
# of field values.
class RtattrMessage < Message
define_type :dev_name, :pattern=>"Z#{IFNAMSIZ}", :default=>EMPTY_STRING
# L2 addresses are presented as ASCII hex. You may optionally include
# colons, hyphens or dots.
# IFInfo.new(:address => "00:11:22:33:44:55") # this is OK

46
lib/netlink/nflog.rb Normal file
View File

@@ -0,0 +1,46 @@
require 'netlink/message'
require 'netlink/nlsocket'
module Netlink
ULOG_NL_EVENT = 111 # from ipv4/netfilter/ipt_ULOG.c
# struct ulog_packet_msg
class UlogPacket < Message
code ULOG_NL_EVENT
field :mark, :ulong
field :timestamp_sec, :long
field :timestamp_usec, :long
field :hook, :uint
field :indev_name, :dev_name
field :outdev_name, :dev_name
field :data_len, :size_t
field :prefix, :pattern=>"Z#{ULOG_PREFIX_LEN}", :default=>EMPTY_STRING
field :mac_len, :uchar
field :mac, :pattern=>"a#{ULOG_MAC_LEN}", :default=>EMPTY_STRING
field :payload, :binary
def after_parse #:nodoc:
mac.slice!(mac_len..-1) if mac.length > mac_len
payload.slice!(data_len..-1) if payload.length > mac_len
end
end
module NFLog
class Socket < NLSocket
# Create a socket to listen for ulog packets. You must pass :group=>N
# (where N is 1 to 32) or :groups=>bitmap to listen on multiple groups
def initialize(opt={})
unless opt[:groups]
opt[:groups] = 1 << (opt.fetch(:group) - 1)
end
super(opt.merge(:protocol => Netlink::NETLINK_NFLOG))
end
# Receive packets and yield them to the block
def dequeue_packets(&blk)
receive_stream(ULOG_NL_EVENT, &blk)
end
end
end
end