ruby-pcap 0.7.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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