Add NETFILTER_NFLOG (ULOG) support
This commit is contained in:
14
examples/nflog.rb
Normal file
14
examples/nflog.rb
Normal 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
|
@@ -101,6 +101,11 @@ class CStruct
|
|||||||
end
|
end
|
||||||
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
|
def to_hash
|
||||||
@attrs
|
@attrs
|
||||||
end
|
end
|
||||||
@@ -177,6 +182,7 @@ class CStruct
|
|||||||
data.unpack(self::FORMAT).zip(self::FIELDS).each do |val, key|
|
data.unpack(self::FORMAT).zip(self::FIELDS).each do |val, key|
|
||||||
obj[key] = val
|
obj[key] = val
|
||||||
end
|
end
|
||||||
|
obj.after_parse
|
||||||
obj
|
obj
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -309,4 +309,8 @@ module Netlink
|
|||||||
IPQM_VERDICT = 18
|
IPQM_VERDICT = 18
|
||||||
IPQM_PACKET = 19
|
IPQM_PACKET = 19
|
||||||
IPQM_MAX = 20
|
IPQM_MAX = 20
|
||||||
|
|
||||||
|
# linux/netfilter_ipv4/ipt_ULOG.h
|
||||||
|
ULOG_MAC_LEN = 80
|
||||||
|
ULOG_PREFIX_LEN = 32
|
||||||
end
|
end
|
||||||
|
@@ -16,14 +16,18 @@ module Netlink
|
|||||||
field :timestamp_sec, :long
|
field :timestamp_sec, :long
|
||||||
field :timestamp_usec, :long
|
field :timestamp_usec, :long
|
||||||
field :hook, :uint
|
field :hook, :uint
|
||||||
field :indev_name, :pattern => "Z#{IFNAMSIZ}", :default => EMPTY_STRING
|
field :indev_name, :dev_name
|
||||||
field :outdev_name, :pattern => "Z#{IFNAMSIZ}", :default => EMPTY_STRING
|
field :outdev_name, :dev_name
|
||||||
field :hw_protocol, :ns
|
field :hw_protocol, :ns
|
||||||
field :hw_type, :ushort
|
field :hw_type, :ushort
|
||||||
field :hw_addrlen, :uchar
|
field :hw_addrlen, :uchar
|
||||||
field :hw_addr, :pattern => "a8", :default => EMPTY_STRING
|
field :hw_addr, :pattern => "a8", :default => EMPTY_STRING
|
||||||
field :data_len, :size_t
|
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
|
end
|
||||||
|
|
||||||
# struct ipq_verdict_msg
|
# struct ipq_verdict_msg
|
||||||
|
@@ -18,11 +18,15 @@ module Netlink
|
|||||||
# Use RtattrMessage instead for messages which are followed by variable rtattrs.
|
# Use RtattrMessage instead for messages which are followed by variable rtattrs.
|
||||||
class Message < CStruct
|
class Message < CStruct
|
||||||
# Map of numeric message type code => message class
|
# Map of numeric message type code => message class
|
||||||
|
# (TODO: should these be scoped to NETLINK_* protocol id?)
|
||||||
CODE_TO_MESSAGE = {}
|
CODE_TO_MESSAGE = {}
|
||||||
|
|
||||||
# Define which message type code(s) to build using this structure
|
# Define which message type code(s) to build using this structure
|
||||||
def self.code(*codes)
|
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
|
end
|
||||||
|
|
||||||
NLMSG_ALIGNTO_1 = NLMSG_ALIGNTO-1 #:nodoc:
|
NLMSG_ALIGNTO_1 = NLMSG_ALIGNTO-1 #:nodoc:
|
||||||
@@ -51,6 +55,8 @@ module Netlink
|
|||||||
# specify :pack and :unpack lambdas to do higher-level conversion
|
# specify :pack and :unpack lambdas to do higher-level conversion
|
||||||
# of field values.
|
# of field values.
|
||||||
class RtattrMessage < Message
|
class RtattrMessage < Message
|
||||||
|
define_type :dev_name, :pattern=>"Z#{IFNAMSIZ}", :default=>EMPTY_STRING
|
||||||
|
|
||||||
# L2 addresses are presented as ASCII hex. You may optionally include
|
# L2 addresses are presented as ASCII hex. You may optionally include
|
||||||
# colons, hyphens or dots.
|
# colons, hyphens or dots.
|
||||||
# IFInfo.new(:address => "00:11:22:33:44:55") # this is OK
|
# IFInfo.new(:address => "00:11:22:33:44:55") # this is OK
|
||||||
|
46
lib/netlink/nflog.rb
Normal file
46
lib/netlink/nflog.rb
Normal 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
|
Reference in New Issue
Block a user