Module: Ethernet::RawSocketFactory

Defined in:
lib/ethernet/raw_socket_factory.rb

Overview

Low-level socket creation functionality.

Class Method Summary collapse

Class Method Details

.all_ethernet_protocolsObject

The protocol number for listening to all ethernet protocols.



59
60
61
62
63
64
65
66
# File 'lib/ethernet/raw_socket_factory.rb', line 59

def all_ethernet_protocols
  case RUBY_PLATFORM
  when /linux/
    3  # cat /usr/include/linux/if_ether.h | grep ETH_P_ALL
  else
    raise "Unsupported platform #{RUBY_PLATFORM}"
  end
end

.get_interface_number(eth_device) ⇒ Object

The interface number for an Ethernet interface.



44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/ethernet/raw_socket_factory.rb', line 44

def get_interface_number(eth_device)
  case RUBY_PLATFORM
  when /linux/
    # /usr/include/net/if.h, structure ifreq
    ifreq = [eth_device].pack 'a32'
    # 0x8933 is SIOCGIFINDEX in /usr/include/bits/ioctls.h
    socket.ioctl 0x8933, ifreq
    ifreq[16, 4].unpack('I').first
  else
    raise "Unsupported platform #{RUBY_PLATFORM}"
  end
end

.htons(short_integer) ⇒ Object

Converts a 16-bit integer from host-order to network-order.



83
84
85
# File 'lib/ethernet/raw_socket_factory.rb', line 83

def htons(short_integer)
  [short_integer].pack('n').unpack('S').first
end

.raw_address_familyObject

The AF / PF number for raw sockets.



70
71
72
73
74
75
76
77
78
79
# File 'lib/ethernet/raw_socket_factory.rb', line 70

def raw_address_family
  case RUBY_PLATFORM
  when /linux/
    17  # cat /usr/include/bits/socket.h | grep PF_PACKET
  when /darwin/
    18  # cat /usr/include/sys/socket.h | grep AF_LINK
  else
    raise "Unsupported platform #{RUBY_PLATFORM}"
  end
end

.set_socket_eth_device(socket, eth_device, ether_type) ⇒ Object

Sets the Ethernet interface and protocol type for a socket.



28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/ethernet/raw_socket_factory.rb', line 28

def set_socket_eth_device(socket, eth_device, ether_type)
  case RUBY_PLATFORM
  when /linux/
    if_number = get_interface_number eth_device
    # struct sockaddr_ll in /usr/include/linux/if_packet.h
    socket_address = [raw_address_family, htons(ether_type), if_number,
                      0xFFFF, 0, 0, ""].pack 'SSISCCa8'
    socket.bind socket_address
  else
    raise "Unsupported platform #{RUBY_PLATFORM}"
  end
  socket
end

.socket(eth_device = nil, ether_type = nil) ⇒ Object

A raw socket sends and receives raw Ethernet frames.

Args:

eth_device:: device name for the Ethernet card, e.g. 'eth0'
ether_type:: only receive Ethernet frames with this protocol number


18
19
20
21
22
23
24
# File 'lib/ethernet/raw_socket_factory.rb', line 18

def self.socket(eth_device = nil, ether_type = nil)
  ether_type ||= all_ethernet_protocols
  socket = Socket.new raw_address_family, Socket::SOCK_RAW, htons(ether_type)
  socket.setsockopt Socket::SOL_SOCKET, Socket::SO_BROADCAST, true
  set_socket_eth_device(socket, eth_device, ether_type) if eth_device
  socket
end