ruby-pcap 0.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,134 @@
1
+ /*
2
+ * ruby_pcap.h
3
+ *
4
+ * $Id: ruby_pcap.h,v 1.4 2000/08/13 06:56:15 fukusima Exp $
5
+ *
6
+ * Copyright (C) 1998-2000 Masaki Fukushima
7
+ */
8
+
9
+ #ifndef RUBY_PCAP_H
10
+ #define RUBY_PCAP_H
11
+
12
+ #include "ruby.h"
13
+ #include <pcap.h>
14
+ #include <stdio.h>
15
+ #include <netinet/in.h>
16
+ #include <netinet/in_systm.h>
17
+ #include <netinet/ip.h>
18
+ #include <arpa/inet.h>
19
+ #ifndef IP_OFFMASK
20
+ # define IP_OFFMASK 0x1fff
21
+ #endif
22
+ #ifdef linux
23
+ # define __FAVOR_BSD
24
+ #endif
25
+ #include <netinet/tcp.h>
26
+ #include <netinet/udp.h>
27
+ #include <netinet/ip_icmp.h>
28
+ #include <sys/socket.h>
29
+ #include <netdb.h>
30
+
31
+ #ifdef DEBUG
32
+ # define DEBUG_PRINT(x) do {\
33
+ ((RTEST(ruby_debug) && RTEST(ruby_verbose))?\
34
+ (fprintf(stderr, "%s\n", x),fflush(stderr)) : 0)\
35
+ } while (0)
36
+ #else
37
+ # define DEBUG_PRINT(x) do {} while (0)
38
+ #endif
39
+
40
+ #define UINT32_2_NUM(i) rb_uint2inum(i)
41
+ #ifndef UINT2NUM
42
+ # define UINT2NUM(i) rb_uint2inum(i)
43
+ #endif
44
+ #define MIN(x, y) ((x)<(y) ? (x) : (y))
45
+
46
+
47
+ #define PACKET_MARSHAL_VERSION 1
48
+
49
+ /* ruby config.h defines WORDS_BIGENDIAN if big-endian */
50
+ struct packet_object_header {
51
+ #ifdef WORDS_BIGENDIAN
52
+ u_char version:4; /* marshal format version */
53
+ u_char flags:4; /* flags */
54
+ #else
55
+ u_char flags:4; /* flags */
56
+ u_char version:4; /* marshal format version */
57
+ #endif
58
+ #define POH_UDATA 0x01 /* flag: user data exists */
59
+ #define POH_RSVD1 0x02 /* (reserved) */
60
+ #define POH_RSVD2 0x03 /* (reserved) */
61
+ #define POH_RSVD3 0x04 /* (reserved) */
62
+ u_char dl_type; /* data-link type (DLT_*) */
63
+ u_short layer3_off; /* layer 3 header offset */
64
+ u_short layer4_off; /* layer 4 header offset */
65
+ u_short layer5_off; /* layer 5 header offset */
66
+ #define OFF_NONEXIST 0xffff /* offset value for non-existent layer */
67
+ struct pcap_pkthdr pkthdr; /* pcap packet header */
68
+ };
69
+
70
+ struct packet_object {
71
+ struct packet_object_header hdr; /* packet object header */
72
+ u_char *data; /* packet data */
73
+ VALUE udata; /* user data */
74
+ };
75
+
76
+ #define PKTFLAG_TEST(pkt, flag) ((pkt)->hdr.flags & (flag))
77
+ #define PKTFLAG_SET(pkt, flag, val) \
78
+ ((val) ? ((pkt)->hdr.flags |= (flag)) : ((pkt)->hdr.flags &= ~(flag)))
79
+
80
+ #define LAYER2_HDR(pkt) ((pkt)->data)
81
+ #define LAYER3_HDR(pkt) ((pkt)->data + (pkt)->hdr.layer3_off)
82
+ #define LAYER4_HDR(pkt) ((pkt)->data + (pkt)->hdr.layer4_off)
83
+ #define LAYER5_HDR(pkt) ((pkt)->data + (pkt)->hdr.layer5_off)
84
+
85
+ #define GetPacket(obj, pkt) Data_Get_Struct(obj, struct packet_object, pkt)
86
+ #define Caplen(pkt, from) ((pkt)->hdr.pkthdr.caplen - (from))
87
+ #define CheckTruncate(pkt, from, need, emsg) (\
88
+ (from) + (need) > (pkt)->hdr.pkthdr.caplen ? \
89
+ rb_raise(eTruncatedPacket, (emsg)) : 0 \
90
+ )
91
+
92
+ #define IsKindOf(v, class) RTEST(rb_obj_is_kind_of(v, class))
93
+ #define CheckClass(v, class) ((IsKindOf(v, class)) ? 0 :\
94
+ rb_raise(rb_eTypeError, "wrong type %s (expected %s)",\
95
+ rb_class2name(CLASS_OF(v)), rb_class2name(class)))
96
+
97
+
98
+ /* Pcap.c */
99
+ extern VALUE mPcap, rbpcap_convert;
100
+ extern VALUE ePcapError;
101
+ extern VALUE eTruncatedPacket;
102
+ extern VALUE cFilter;
103
+ void Init_pcap(void);
104
+ VALUE filter_match(VALUE self, VALUE v_pkt);
105
+
106
+ /* packet.c */
107
+ extern VALUE cPacket;
108
+ void Init_packet(void);
109
+ VALUE new_packet(const u_char *, const struct pcap_pkthdr *, int);
110
+
111
+ /* ip_packet.c */
112
+ #define IP_HDR(pkt) ((struct ip *)LAYER3_HDR(pkt))
113
+ #define IP_DATA(pkt) ((u_char *)LAYER4_HDR(pkt))
114
+ extern VALUE cIPPacket;
115
+ void Init_ip_packet(void);
116
+ VALUE setup_ip_packet(struct packet_object *, int);
117
+ VALUE new_ipaddr(struct in_addr *);
118
+
119
+ /* tcp_packet.c */
120
+ extern VALUE cTCPPacket;
121
+ void Init_tcp_packet(void);
122
+ VALUE setup_tcp_packet(struct packet_object *, int);
123
+
124
+ /* udp_packet.c */
125
+ extern VALUE cUDPPacket;
126
+ void Init_udp_packet(void);
127
+ VALUE setup_udp_packet(struct packet_object *, int);
128
+
129
+ /* icmp_packet.c */
130
+ extern VALUE cICMPPacket;
131
+ void Init_icmp_packet(void);
132
+ VALUE setup_icmp_packet(struct packet_object *, int);
133
+
134
+ #endif /* RUBY_PCAP_H */
@@ -0,0 +1,121 @@
1
+ /*
2
+ * tcp_packet.c
3
+ *
4
+ * $Id: tcp_packet.c,v 1.1.1.1 1999/10/27 09:54:38 fukusima Exp $
5
+ *
6
+ * Copyright (C) 1998, 1999 Masaki Fukushima
7
+ */
8
+
9
+ #include "ruby_pcap.h"
10
+ #include <limits.h>
11
+
12
+ #define TCP_HDR(pkt) ((struct tcphdr *)LAYER4_HDR(pkt))
13
+ #define TCP_DATA(pkt) ((u_char *)LAYER5_HDR(pkt))
14
+ #define TCP_DATALEN(pkt) (ntohs(IP_HDR(pkt)->ip_len) - \
15
+ (IP_HDR(pkt)->ip_hl + TCP_HDR(pkt)->th_off) * 4)
16
+
17
+ VALUE cTCPPacket;
18
+
19
+ #define CheckTruncateTcp(pkt, need) \
20
+ CheckTruncate(pkt, pkt->hdr.layer4_off, need, "truncated TCP")
21
+
22
+ VALUE
23
+ setup_tcp_packet(pkt, tl_len)
24
+ struct packet_object *pkt;
25
+ int tl_len;
26
+ {
27
+ VALUE class;
28
+
29
+ DEBUG_PRINT("setup_tcp_packet");
30
+
31
+ class = cTCPPacket;
32
+ if (tl_len > 20) {
33
+ int hl = TCP_HDR(pkt)->th_off * 4;
34
+ int layer5_len = tl_len - hl;
35
+ if (layer5_len > 0) {
36
+ pkt->hdr.layer5_off = pkt->hdr.layer4_off + hl;
37
+ /* upper layer */
38
+ }
39
+ }
40
+ return class;
41
+ }
42
+
43
+ #define TCPP_METHOD(func, need, val) \
44
+ static VALUE\
45
+ (func)(self)\
46
+ VALUE self;\
47
+ {\
48
+ struct packet_object *pkt;\
49
+ struct tcphdr *tcp;\
50
+ DEBUG_PRINT(#func);\
51
+ GetPacket(self, pkt);\
52
+ CheckTruncateTcp(pkt, (need));\
53
+ tcp = TCP_HDR(pkt);\
54
+ return (val);\
55
+ }
56
+
57
+ TCPP_METHOD(tcpp_sport, 2, INT2FIX(ntohs(tcp->th_sport)))
58
+ TCPP_METHOD(tcpp_dport, 4, INT2FIX(ntohs(tcp->th_dport)))
59
+ TCPP_METHOD(tcpp_seq, 8, UINT32_2_NUM(ntohl(tcp->th_seq)))
60
+ TCPP_METHOD(tcpp_acknum, 12, UINT32_2_NUM(ntohl(tcp->th_ack)))
61
+ TCPP_METHOD(tcpp_off, 13, INT2FIX(tcp->th_off))
62
+ TCPP_METHOD(tcpp_flags, 14, INT2FIX(tcp->th_flags))
63
+ TCPP_METHOD(tcpp_win, 16, INT2FIX(ntohs(tcp->th_win)))
64
+ TCPP_METHOD(tcpp_sum, 18, INT2FIX(ntohs(tcp->th_sum)))
65
+ TCPP_METHOD(tcpp_urp, 20, INT2FIX(ntohs(tcp->th_urp)))
66
+
67
+ #define TCPP_FLAG(func, flag) \
68
+ TCPP_METHOD(func, 14, (tcp->th_flags & flag) ? Qtrue : Qfalse)
69
+ TCPP_FLAG(tcpp_fin, TH_FIN)
70
+ TCPP_FLAG(tcpp_syn, TH_SYN)
71
+ TCPP_FLAG(tcpp_rst, TH_RST)
72
+ TCPP_FLAG(tcpp_psh, TH_PUSH)
73
+ TCPP_FLAG(tcpp_ack, TH_ACK)
74
+ TCPP_FLAG(tcpp_urg, TH_URG)
75
+
76
+ static VALUE
77
+ tcpp_data(self)
78
+ VALUE self;
79
+ {
80
+ struct packet_object *pkt;
81
+ VALUE v_len;
82
+ int len;
83
+
84
+ DEBUG_PRINT("tcpp_data");
85
+ GetPacket(self, pkt);
86
+
87
+ if (pkt->hdr.layer5_off == OFF_NONEXIST) return Qnil;
88
+
89
+ len = MIN(Caplen(pkt, pkt->hdr.layer5_off), TCP_DATALEN(pkt));
90
+ if (len < 1) return Qnil;
91
+ return rb_str_new(TCP_DATA(pkt), len);
92
+ }
93
+
94
+ void
95
+ Init_tcp_packet(void)
96
+ {
97
+ DEBUG_PRINT("Init_tcp_packet");
98
+
99
+ /* define class TcpPacket */
100
+ cTCPPacket = rb_define_class_under(mPcap, "TCPPacket", cIPPacket);
101
+
102
+ rb_define_method(cTCPPacket, "tcp_sport", tcpp_sport, 0);
103
+ rb_define_method(cTCPPacket, "sport", tcpp_sport, 0);
104
+ rb_define_method(cTCPPacket, "tcp_dport", tcpp_dport, 0);
105
+ rb_define_method(cTCPPacket, "dport", tcpp_dport, 0);
106
+ rb_define_method(cTCPPacket, "tcp_seq", tcpp_seq, 0);
107
+ rb_define_method(cTCPPacket, "tcp_ack", tcpp_acknum, 0);
108
+ rb_define_method(cTCPPacket, "tcp_off", tcpp_off, 0);
109
+ rb_define_method(cTCPPacket, "tcp_hlen", tcpp_off, 0);
110
+ rb_define_method(cTCPPacket, "tcp_flags", tcpp_flags, 0);
111
+ rb_define_method(cTCPPacket, "tcp_win", tcpp_win, 0);
112
+ rb_define_method(cTCPPacket, "tcp_sum", tcpp_sum, 0);
113
+ rb_define_method(cTCPPacket, "tcp_urp", tcpp_urp, 0);
114
+ rb_define_method(cTCPPacket, "tcp_fin?", tcpp_fin, 0);
115
+ rb_define_method(cTCPPacket, "tcp_syn?", tcpp_syn, 0);
116
+ rb_define_method(cTCPPacket, "tcp_rst?", tcpp_rst, 0);
117
+ rb_define_method(cTCPPacket, "tcp_psh?", tcpp_psh, 0);
118
+ rb_define_method(cTCPPacket, "tcp_ack?", tcpp_ack, 0);
119
+ rb_define_method(cTCPPacket, "tcp_urg?", tcpp_urg, 0);
120
+ rb_define_method(cTCPPacket, "tcp_data", tcpp_data, 0);
121
+ }
@@ -0,0 +1,96 @@
1
+ /*
2
+ * udp_packet.c
3
+ *
4
+ * $Id: udp_packet.c,v 1.1.1.1 1999/10/27 09:54:38 fukusima Exp $
5
+ *
6
+ * Copyright (C) 1999 Masaki Fukushima
7
+ */
8
+
9
+ #include "ruby_pcap.h"
10
+ #include <limits.h>
11
+
12
+ #define UDP_HDR(pkt) ((struct udphdr *)LAYER4_HDR(pkt))
13
+ #define UDP_DATA(pkt) ((u_char *)LAYER5_HDR(pkt))
14
+ #define UDP_LENGTH(pkt) (ntohs(UDP_HDR(pkt)->uh_ulen))
15
+
16
+ VALUE cUDPPacket;
17
+
18
+ #define CheckTruncateUdp(pkt, need) \
19
+ CheckTruncate(pkt, pkt->hdr.layer4_off, need, "truncated UDP")
20
+
21
+ VALUE
22
+ setup_udp_packet(pkt, tl_len)
23
+ struct packet_object *pkt;
24
+ int tl_len;
25
+ {
26
+ VALUE class;
27
+
28
+ DEBUG_PRINT("setup_udp_packet");
29
+
30
+ class = cUDPPacket;
31
+ if (tl_len > 8) {
32
+ int hl = 8;
33
+ int layer5_len;
34
+
35
+ tl_len = MIN(tl_len, UDP_LENGTH(pkt));
36
+ layer5_len = tl_len - hl;
37
+ if (layer5_len > 0) {
38
+ pkt->hdr.layer5_off = pkt->hdr.layer4_off + hl;
39
+ /* upper layer */
40
+ }
41
+ }
42
+ return class;
43
+ }
44
+
45
+ #define UDPP_METHOD(func, need, val) \
46
+ static VALUE\
47
+ (func)(self)\
48
+ VALUE self;\
49
+ {\
50
+ struct packet_object *pkt;\
51
+ struct udphdr *udp;\
52
+ DEBUG_PRINT(#func);\
53
+ GetPacket(self, pkt);\
54
+ CheckTruncateUdp(pkt, (need));\
55
+ udp = UDP_HDR(pkt);\
56
+ return (val);\
57
+ }
58
+
59
+ UDPP_METHOD(udpp_sport, 2, INT2FIX(ntohs(udp->uh_sport)))
60
+ UDPP_METHOD(udpp_dport, 4, INT2FIX(ntohs(udp->uh_dport)))
61
+ UDPP_METHOD(udpp_len, 6, INT2FIX(ntohs(udp->uh_ulen)))
62
+ UDPP_METHOD(udpp_sum, 8, INT2FIX(ntohs(udp->uh_sum)))
63
+
64
+ static VALUE
65
+ udpp_data(self)
66
+ VALUE self;
67
+ {
68
+ struct packet_object *pkt;
69
+ int len;
70
+
71
+ DEBUG_PRINT("udpp_data");
72
+ GetPacket(self, pkt);
73
+ CheckTruncateUdp(pkt, 8);
74
+
75
+ if (pkt->hdr.layer5_off == OFF_NONEXIST) return Qnil;
76
+
77
+ len = MIN(Caplen(pkt, pkt->hdr.layer5_off), UDP_LENGTH(pkt)-8);
78
+ return rb_str_new(UDP_DATA(pkt), len);
79
+ }
80
+
81
+ void
82
+ Init_udp_packet(void)
83
+ {
84
+ DEBUG_PRINT("Init_udp_packet");
85
+
86
+ /* define class UdpPacket */
87
+ cUDPPacket = rb_define_class_under(mPcap, "UDPPacket", cIPPacket);
88
+
89
+ rb_define_method(cUDPPacket, "udp_sport", udpp_sport, 0);
90
+ rb_define_method(cUDPPacket, "sport", udpp_sport, 0);
91
+ rb_define_method(cUDPPacket, "udp_dport", udpp_dport, 0);
92
+ rb_define_method(cUDPPacket, "dport", udpp_dport, 0);
93
+ rb_define_method(cUDPPacket, "udp_len", udpp_len, 0);
94
+ rb_define_method(cUDPPacket, "udp_sum", udpp_sum, 0);
95
+ rb_define_method(cUDPPacket, "udp_data", udpp_data, 0);
96
+ }
@@ -0,0 +1,80 @@
1
+
2
+ module Pcap
3
+ class Packet
4
+ def to_s
5
+ 'Some packet'
6
+ end
7
+
8
+ def inspect
9
+ "#<#{self.class}: #{self}>"
10
+ end
11
+ end
12
+
13
+ class IPPacket
14
+ def to_s
15
+ "#{ip_src} > #{ip_dst}"
16
+ end
17
+ end
18
+
19
+ class TCPPacket
20
+ def tcp_data_len
21
+ ip_len - 4 * (ip_hlen + tcp_hlen)
22
+ end
23
+
24
+ def tcp_flags_s
25
+ return \
26
+ (tcp_urg? ? 'U' : '.') +
27
+ (tcp_ack? ? 'A' : '.') +
28
+ (tcp_psh? ? 'P' : '.') +
29
+ (tcp_rst? ? 'R' : '.') +
30
+ (tcp_syn? ? 'S' : '.') +
31
+ (tcp_fin? ? 'F' : '.')
32
+ end
33
+
34
+ def to_s
35
+ "#{src}:#{sport} > #{dst}:#{dport} #{tcp_flags_s}"
36
+ end
37
+
38
+ def src_mac_address
39
+ return unpack_hex_string(raw_data[6, 12])
40
+ end
41
+
42
+ def dst_mac_address
43
+ return unpack_hex_string(raw_data[0, 6])
44
+ end
45
+
46
+ def unpack_hex_string(hex)
47
+ return hex.unpack('H2H2H2H2H2H2').join('')
48
+ end
49
+ end
50
+
51
+ class UDPPacket
52
+ def to_s
53
+ "#{src}:#{sport} > #{dst}:#{dport} len #{udp_len} sum #{udp_sum}"
54
+ end
55
+ end
56
+
57
+ class ICMPPacket
58
+ def to_s
59
+ "#{src} > #{dst}: icmp: #{icmp_typestr}"
60
+ end
61
+ end
62
+
63
+ #
64
+ # Backword compatibility
65
+ #
66
+ IpPacket = IPPacket
67
+ IpAddress = IPAddress
68
+ TcpPacket = TCPPacket
69
+ UdpPacket = UDPPacket
70
+
71
+ end
72
+
73
+ class Time
74
+ # tcpdump style format
75
+ def tcpdump
76
+ sprintf "%0.2d:%0.2d:%0.2d.%0.6d", hour, min, sec, tv_usec
77
+ end
78
+ end
79
+
80
+ autoload :Pcaplet, 'pcaplet'
@@ -0,0 +1,127 @@
1
+ require 'pcap'
2
+ require 'optparse'
3
+
4
+ def pcaplet_usage()
5
+ $stderr.print <<END
6
+ Usage: #{File.basename $0} [ -dnv ] [ -i interface | -r file ]
7
+ #{' ' * File.basename($0).length} [ -c count ] [ -s snaplen ] [ filter ]
8
+ Options:
9
+ -n do not convert address to name
10
+ -d debug mode
11
+ -v verbose mode
12
+ END
13
+ end
14
+
15
+ module Pcap
16
+ class Pcaplet
17
+ def usage(status, msg = nil)
18
+ $stderr.puts msg if msg
19
+ pcaplet_usage
20
+ exit(status)
21
+ end
22
+
23
+ def initialize(args = nil)
24
+ if args
25
+ ARGV[0,0] = args.split(/\s+/)
26
+ end
27
+ @device = nil
28
+ @rfile = nil
29
+ @count = -1
30
+ @snaplen = 68
31
+ @log_packets = false
32
+ @duplicated = nil
33
+
34
+ opts = OptionParser.new do |opts|
35
+ opts.on('-d') {$DEBUG = true}
36
+ opts.on('-v') {$VERBOSE = true}
37
+ opts.on('-n') {Pcap.convert = false}
38
+ opts.on('-i IFACE') {|s| @device = s}
39
+ opts.on('-r FILE') {|s| @rfile = s}
40
+ opts.on('-c COUNT', OptionParser::DecimalInteger) {|i| @count = i}
41
+ opts.on('-s LEN', OptionParser::DecimalInteger) {|i| @snaplen = i}
42
+ opts.on('-l') { @log_packets = true }
43
+ end
44
+ begin
45
+ opts.parse!
46
+ rescue
47
+ usage(1)
48
+ end
49
+
50
+ @filter = ARGV.join(' ')
51
+
52
+ # check option consistency
53
+ usage(1) if @device && @rfile
54
+ if !@device and !@rfile
55
+ @device = Pcap.lookupdev
56
+ end
57
+
58
+ # open
59
+ begin
60
+ if @device
61
+ @capture = Capture.open_live(@device, @snaplen)
62
+ elsif @rfile
63
+ if @rfile !~ /\.gz$/
64
+ @capture = Capture.open_offline(@rfile)
65
+ else
66
+ $stdin = IO.popen("gzip -dc < #@rfile", 'r')
67
+ @capture = Capture.open_offline('-')
68
+ end
69
+ end
70
+ @capture.setfilter(@filter)
71
+ rescue PcapError, ArgumentError
72
+ $stdout.flush
73
+ $stderr.puts $!
74
+ exit(1)
75
+ end
76
+ end
77
+
78
+ attr('capture')
79
+
80
+ def add_filter(f)
81
+ if @filter == nil || @filter =~ /^\s*$/ # if empty
82
+ @filter = f
83
+ else
84
+ f = f.source if f.is_a? Filter
85
+ @filter = "( #{@filter} ) and ( #{f} )"
86
+ end
87
+ @capture.setfilter(@filter)
88
+ end
89
+
90
+ def each_packet(&block)
91
+ begin
92
+ @duplicated ||= (RUBY_PLATFORM =~ /linux/ && @device == "lo")
93
+ if !@duplicated
94
+ @capture.loop(@count, &block)
95
+ else
96
+ flip = true
97
+ @capture.loop(@count) do |pkt|
98
+ flip = (! flip)
99
+ next if flip
100
+
101
+ block.call pkt
102
+ end
103
+ end
104
+ rescue Exception => e
105
+ $stderr.puts "exception when looping over each packet loop: #{e.inspect}"
106
+ raise
107
+ ensure
108
+ # print statistics if live
109
+ if @device && @log_packets
110
+ stat = @capture.stats
111
+ if stat
112
+ $stderr.print("#{stat.recv} packets received by filter\n");
113
+ $stderr.print("#{stat.drop} packets dropped by kernel\n");
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ alias :each :each_packet
120
+
121
+ def close
122
+ @capture.close
123
+ end
124
+ end
125
+ end
126
+
127
+ Pcaplet = Pcap::Pcaplet