Goal: recreate scratchpad's
ether_ping in my ethernet gem.
AF / PF POSIX Socket API
Ruby learning
ruby array pack() array-->binary string
string unpack string --> array
array first()
attr_reader :to_return is
an alias for returning that instance's to_return.
ether_ping eth0 88B7 001122334455 aa00112233
ether_ping net_interface ether_type 2bytes dest_mac 6byte data 0pad to 64 bytes
scratchpad's
ether_ping, relies on
- scratchpad/bin/
- ether_ping is the client
client = Scratchpad::Ethernet::PingClient.new interface, ether_type, dest_mac
puts client.ping(data)
- ether_ping_server
it seems that calling ether_ping doesn't need ether_ping_server's stuff
- scratchpad/lib/scratchpad/ethernet
- ping.rb has classes: PingServer and PingClient
has
require 'eventmachine' for communication
- raw_ethernet.rb connects to the raw_ethernet stuff
What I did:
1. keep looking at that. Especially socket
http://www.ruby-doc.org/stdlib/libdoc/socket/rdoc/classes/Socket.html
2. ethernet is basically ether_shell renamed, with scratchpad's pinging
3.
Put in system-getifaddr in too
trying
ethernet$ rake
(in /home/haoqili/Desktop/rails/ethernet)
/usr/bin/ruby1.8 -S bundle exec rspec "spec/raw_socket_spec.rb" "spec/ethernet_spec.rb" "spec/socket_wrapper_spec.rb"
/usr/lib/ruby/gems/1.8/gems/rspec-core-2.3.1/lib/rspec/core/backward_compatibility.rb:20:in `const_missing': uninitialized constant ShellStub::Ethernet (NameError)
from /usr/lib/ruby/gems/1.8/gems/rspec-expectations-2.3.0/lib/rspec/expectations/backward_compatibility.rb:6:in `const_missing'
from /home/haoqili/Desktop/rails/ethernet/spec/support/shell_stub.rb:2
from /home/haoqili/Desktop/rails/ethernet/spec/spec_helper.rb:8:in `require'
from /home/haoqili/Desktop/rails/ethernet/spec/spec_helper.rb:8
from /home/haoqili/Desktop/rails/ethernet/spec/spec_helper.rb:8:in `each'
from /home/haoqili/Desktop/rails/ethernet/spec/spec_helper.rb:8
from /home/haoqili/Desktop/rails/ethernet/spec/raw_socket_spec.rb:4:in `require'
from /home/haoqili/Desktop/rails/ethernet/spec/raw_socket_spec.rb:4
from /usr/lib/ruby/gems/1.8/gems/rspec-core-2.3.1/lib/rspec/core/configuration.rb:388:in `load'
from /usr/lib/ruby/gems/1.8/gems/rspec-core-2.3.1/lib/rspec/core/configuration.rb:388:in `load_spec_files'
from /usr/lib/ruby/gems/1.8/gems/rspec-core-2.3.1/lib/rspec/core/configuration.rb:388:in `map'
from /usr/lib/ruby/gems/1.8/gems/rspec-core-2.3.1/lib/rspec/core/configuration.rb:388:in `load_spec_files'
from /usr/lib/ruby/gems/1.8/gems/rspec-core-2.3.1/lib/rspec/core/command_line.rb:18:in `run'
from /usr/lib/ruby/gems/1.8/gems/rspec-core-2.3.1/lib/rspec/core/runner.rb:55:in `run_in_process'
from /usr/lib/ruby/gems/1.8/gems/rspec-core-2.3.1/lib/rspec/core/runner.rb:46:in `run'
from /usr/lib/ruby/gems/1.8/gems/rspec-core-2.3.1/lib/rspec/core/runner.rb:10:in `autorun'
from /usr/bin/rspec:19
rake aborted!
ruby -S bundle exec rspec "spec/raw_socket_spec.rb" "spec/ethernet_spec.rb" "spec/socket_wrapper_spec.rb" failed
(See full trace by running task with --trace)
ethernet$ sudo rake install
(in /home/haoqili/Desktop/rails/ethernet)
Successfully built RubyGem
Name: ethernet
Version: 0.0.0
File: ethernet-0.0.0.gem
Executing "ruby1.8 -S gem install ./pkg/ethernet-0.0.0.gem":
ruby1.8 -S gem install ./pkg/ethernet-0.0.0.gem
Successfully installed ethernet-0.0.0
1 gem installed
Installing ri documentation for ethernet-0.0.0...
Installing RDoc documentation for ethernet-0.0.0...
========
added "s.executables =["ethernet_ping"]" in ethernet.gemspec
/ethernet$ sudo rake install
[sudo] password for haoqili:
(in /home/haoqili/Desktop/rails/ethernet)
Successfully built RubyGem
Name: ethernet
Version: 0.0.0
File: ethernet-0.0.0.gem
Executing "ruby1.8 -S gem install ./pkg/ethernet-0.0.0.gem":
ruby1.8 -S gem install ./pkg/ethernet-0.0.0.gem
Building native extensions. This could take a while...
Successfully installed eventmachine-0.12.10
Successfully installed ethernet-0.0.0
2 gems installed
Installing ri documentation for eventmachine-0.12.10...
Installing ri documentation for ethernet-0.0.0...
Installing RDoc documentation for eventmachine-0.12.10...
Could not find main page README
Could not find main page README
Could not find main page README
Could not find main page README
Installing RDoc documentation for ethernet-0.0.0...
still not found
ethernet$ ethernet_ping
ethernet_ping: command not found
deleted s.executables = ["ethernet_ping"] from ethernet.gemspec
added gem.executables = ["ethernet_ping"] to Rakefile
$ sudo rake install
[sudo] password for haoqili:
(in /home/haoqili/Desktop/rails/ethernet)
Successfully built RubyGem
Name: ethernet
Version: 0.0.0
File: ethernet-0.0.0.gem
Executing "ruby1.8 -S gem install ./pkg/ethernet-0.0.0.gem":
ruby1.8 -S gem install ./pkg/ethernet-0.0.0.gem
Building native extensions. This could take a while...
Successfully installed eventmachine-0.12.10
Successfully installed ethernet-0.0.0
2 gems installed
Installing ri documentation for eventmachine-0.12.10...
Installing ri documentation for ethernet-0.0.0...
Installing RDoc documentation for eventmachine-0.12.10...
Could not find main page README
Could not find main page README
Could not find main page README
Could not find main page README
Installing RDoc documentation for ethernet-0.0.0...
haoqili@stay-focused-hq:18:32:11:~/Desktop/rails/ethernet$ ethernet_ping
Usage: /usr/bin/ethernet_ping net_interface ether_type dest_mac data
net_interface: name of the Ethernet interface, e.g. eth0
ether_type: packet type for the Ethernet II frame, in hex (2 bytes)
dest_mac: destination MAC for the ping packets, in hex (6 bytes)
data: ping packet data, in hex (0-padded to 64 bytes)
haoqili@stay-focused-hq:18:35:52:~/Desktop/rails/ethernet$ sudo ethernet_ping eth0 88B7 001122334455 aa00112233
/usr/lib/ruby/gems/1.8/gems/ethernet-0.0.0/bin/ethernet_ping:22: uninitialized constant Ethernet (NameError)
from /usr/bin/ethernet_ping:19:in `load'
from /usr/bin/ethernet_ping:19
19 load Gem.bin_path('ethernet', 'ethernet_ping', version)
That doesn't look right
* After Victor told me
to add ethernet.rb (and then I did
sudo rake install), the Ethernet NameError is gone, but now I have
$ sudo ethernet_ping eth0 88B7 001122334455 aa00112233
[sudo] password for haoqili:
/usr/lib/ruby/gems/1.8/gems/ethernet-0.0.0/bin/ethernet_ping:22: uninitialized constant Ethernet::PingClient (NameError)
from /usr/bin/ethernet_ping:19:in `load'
from /usr/bin/ethernet_ping:19
* Ah, because I never put in the file about ethernet pinging in "ethernet.rb", so I added this line:
require 'ping.rb' # This is to get ethernet_ping working :P
sudo rake install again
$ sudo ethernet_ping eth0 88B7 001122334455 aa00112233
/usr/lib/ruby/gems/1.8/gems/ethernet-0.0.0/lib/ping.rb:63:in `initialize': undefined method `socket' for Ethernet:Module (NoMethodError)
from /usr/lib/ruby/gems/1.8/gems/ethernet-0.0.0/bin/ethernet_ping:22:in `new'
from /usr/lib/ruby/gems/1.8/gems/ethernet-0.0.0/bin/ethernet_ping:22
from /usr/bin/ethernet_ping:19:in `load'
from /usr/bin/ethernet_ping:19
This is because I put my "socket" method inside the RawSocket module as well, so for methods ".socket" and ".mac", I have to change their prefix from "Ethernet::" to "Ethernet::RawSocket".
I also reordered where the ruby files are stored. Victor told me that the way he set ether_shell up is how it's done by convention. "IDEs have shortcuts that let you navigate between code and spec, as long as things stay where they're supposed to be."
so after "sudo rake install", I tried the above ethernet_ping, but I got another error:
$ sudo ethernet_ping eth0 88B7 001122334455 aa00112233
/usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require': no such file to load -- ethernet/raw_socket.rb (LoadError)
from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'
from /usr/lib/ruby/gems/1.8/gems/ethernet-0.0.0/lib/ethernet.rb:6
from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require'
from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'
from /usr/lib/ruby/gems/1.8/gems/ethernet-0.0.0/bin/ethernet_ping:3
from /usr/bin/ethernet_ping:19:in `load'
from /usr/bin/ethernet_ping:19
This is at commit 1b6daf320e82219a15d52d734dcbb10aff1b5fb6.
The next day, I went to see Victor. He told me to check:
$ ls /usr/lib/ruby/gems/1.8/gems/ethernet-0.0.0/lib
ethernet.rb
Indeed, the ethernet dir was not there.
I did again:
ethernet$ sudo rake install
(in /home/haoqili/Desktop/rails/ethernet)
Successfully built RubyGem
Name: ethernet
Version: 0.0.0
File: ethernet-0.0.0.gem
Executing "ruby1.8 -S gem install ./pkg/ethernet-0.0.0.gem":
ruby1.8 -S gem install ./pkg/ethernet-0.0.0.gem
Building native extensions. This could take a while...
Successfully installed eventmachine-0.12.10
Successfully installed ethernet-0.0.0
2 gems installed
Installing ri documentation for eventmachine-0.12.10...
Installing ri documentation for ethernet-0.0.0...
Installing RDoc documentation for eventmachine-0.12.10...
Could not find main page README
Could not find main page README
Could not find main page README
Could not find main page README
$ ls /usr/lib/ruby/gems/1.8/gems/ethernet-0.0.0/lib
ethernet ethernet.rb
haoqili@stay-focused-hq:15:16:56:~/Desktop/rails/ethernet$ sudo ethernet_ping eth0 88B7 001122334455 aa00112233
Pinging 001122334455...
Fixed!
Shoot. It didn't show up on Wireshark :/
I printed out the source mac, sure it doesn't match eth0's mac address:
eth0 Link encap:Ethernet HWaddr 00:21:70:92:5b:c5
57 class PingClient
58 def initialize(if_name, ether_type, destination_mac)
59 @socket = Ethernet.socket if_name, ether_type
60
61 @source_mac = [Ethernet.get_interface_mac(if_name)].pack('H*')[0, 6]
62 puts "\n the source_mac, is"
63 puts @source_mac.unpack('H*')[0]
ethernet's result:
$ sudo ethernet_ping eth0 88B7 001122334455 aa00112233
the source mac is:
0192b5
Pinging 001122334455...
scratchpad's result: (scratchpad has the working ether_ping)
$ sudo ether_ping eth0 88B7 001122334455 aa00112233
the source_mac, is
002170925bc5
Pinging 001122334455...
This is because ether_shell's raw_socket's .mac() doesn't have "unpack('H*').first", so if I put this back in, pinging would work in ethernet
raw_socket.rb
32 def self.mac(eth_device)
33 case RUBY_PLATFORM
34 when /linux/
35 # /usr/include/net/if.h, structure ifreq
36 ifreq = [eth_device].pack 'a32'
37 # 0x8927 is SIOCGIFHWADDR in /usr/include/bits/ioctls.h
38 socket.ioctl 0x8927, ifreq
40 #ifreq[18, 6] #in scratchpad's raw_ethernet, then says .unpack('H*').first
41 # because raw socket should return raw data
42 # leaving higher layers for presentation issues
43 else
add it in here instead
ping.rb
66 @source_mac = [Ethernet::RawSocket.mac(eth_device).unpack('H*').first].pack('H*')[0, 6]
Yay worked!
commit: bff1c0ca79ed679aae77e5e6199c2aaf3e75fdc9
:) ethernet_ping works! Try with 'sudo ethernet_ping eth0 88B7 001122334455 aa00112233' and see it in Wireshark's eth0