Showing posts with label windows. Show all posts
Showing posts with label windows. Show all posts

Sunday, May 1, 2011

Ruby Raw Socket for Windows

About Raw Sockets in general:
- Wikipedia article: A raw socket is a socket that allows direct sending and receiving of network packets by applications, bypassing all encapsulation in the networking software of the operating system.

Linux specific:
- terminal type:
man 7 raw
to read about raw sockets
- might be useful #1
- might be useful #2


Windows specific:
- libpcap-1.1.1./pcap-win32.c has the wsockinit() function, not very useful though
- Windows uses Winsock(Wiki article)
- Very good Windows raw socket explaination also with code: Raw Sockets and Windows
First of all, it must be understood very clearly that raw sockets is not a feature of the network API (although it must be present there as an option) but of the OS protocol stack. To implement raw sockets, all we have to do is to inform the OS that the packet buffer we are providing will have the header and so the OS should transmit it as is without "adding any header"; that's all, nothing more to do. The Unix operating system has raw socket support since ancient times. But the problem is with Windows. None of Windows 95, 98, 98SE supported raw sockets. Raw sockets became available on Windows from Windows 2000; Windows XP continued this. But suddenly, raw socket support was removed from Windows XP through a patch in SP2. Vista probably doesn't have it. Windows 95, 98, 98SE do not support raw sockets, but this doesn't end the story. If you want the facility, then the solution is to use a third party packet driver like Winpcap. Such packet drivers will do your task irrespective of what the OS likes and dislikes. Windows XP and XP SP1 have full raw socket support and so life is easy. So if you want to do raw socketing on Windows, then either use Winpcap or don't feel desperate to install SP2, or otherwise use Windows 2003 which, as per my knowledge, has raw socket support. So let's brief up.
-----
Windows 95, 98, 98SE, NT4.0 -- Only raw ICMP and IGMP with restricted features.
Windows 2000, XP, XP SP1, 2003 -- Full raw socket support for both receiving and sending purposes.
Windows XP SP2 -- Only raw ICMP, IGMP, and UDP with proper source address (IP spoofing restricted) can be sent. But, full raw sockets can be received, which means you can sniff all incoming data and read their headers.
Note : Winsock Ver. >=2.0
----
So if your system doesn't support raw sockets, then switch to Linux or use Winpcap.

- Very useful Winsock FAQ
--- question: Do I must have a TCP/IP?
) What do I need to run WinSock applications?
----------------------------------------------
Interesting how after "rake install" in Windows, the Gemfile.lock shows "x86-mingw32" as well as "ruby" under "PLATFORMS"

----------

Using WinSock applications to access the Internet requires:

- A suitable connection to the Internet.
- A TCP/IP stack (which includes it's own WINSOCK.DLL).

=====================
Trying to see if existing Linux socket would work on Windows:

commit 9a5b019bea6f62f22cf90e2c6eaf0c0637387e7f
take out unnecessary raise exception. Hopefully windows socket can work?


Administrator@HAOQI-4F34C3203 ~/Desktop/ethernet/spec/ethernet (master)
$ rspec raw_socket_spec.rb
FFFFFF

Failures:

  1) RawSocket mac should have 6 bytes
     Failure/Error: let(:mac) { Ethernet::RawSocket.mac eth_device }
     RuntimeError:
       Unsupported platform i386-mingw32
     # c:/Documents and Settings/Administrator/Desktop/ethernet/lib/ethernet/raw
_socket.rb:121:in `all_ethernet_protocols'
     # c:/Documents and Settings/Administrator/Desktop/ethernet/lib/ethernet/raw
_socket.rb:24:in `socket'
     # c:/Documents and Settings/Administrator/Desktop/ethernet/lib/ethernet/raw
_socket.rb:49:in `mac'
     # ./raw_socket_spec.rb:8:in `block (2 levels) in '
     # ./raw_socket_spec.rb:17:in `block (3 levels) in '

  2) RawSocket mac should match ifconfig output
     same as above

  3) RawSocket socket should be able to receive data
     Failure/Error: before { @socket = Ethernet::RawSocket.socket eth_device }
     RuntimeError:
       Unsupported platform i386-mingw32
     # c:/Documents and Settings/Administrator/Desktop/ethernet/lib/ethernet/raw
_socket.rb:121:in `all_ethernet_protocols'
     # c:/Documents and Settings/Administrator/Desktop/ethernet/lib/ethernet/raw
_socket.rb:24:in `socket'
     # ./raw_socket_spec.rb:28:in `block (3 levels) in '

  4) RawSocket socket should output a packet
     same as above

  5) RawSocket socket should receive some network noise
     same as above

  6) RawSocket testing listing all network devices should list the devices
     Failure/Error: device_macaddrs.each do |key, value|
     NoMethodError:
       undefined method `each' for nil:NilClass
     # ./raw_socket_spec.rb:48:in `block (3 levels) in '

Finished in 0 seconds
6 examples, 6 failures

Currently, I have all the errors because of the highlighted line above. Looking at that:
23   def self.socket(eth_device = nil, ether_type = nil)
 24     ether_type ||= all_ethernet_protocols
 25     socket = Socket.new raw_address_family, Socket::SOCK_RAW, htons(ether_type)
...
115     # The protocol number for listening to all ethernet protocols.
116     def all_ethernet_protocols
117       case RUBY_PLATFORM
118       when /linux/
119         3
120       else
121         raise "Unsupported platform #{RUBY_PLATFORM}"
122       end
123     end
What "||=" means in "ether_type ||= all_ethernet_protocols"
Victor's answer:
It's a trick in modern languages. || is boolean OR, and the way it's implemented is a || b returns a if it is a true value, otherwise it returns b. You can think of it for a bit and convince yourself that this fulfills the contract for OR. ||= is used to specify default values -- if ether_type was nil or false, it becomes all_ethernet_protocols. Otherwise it doesn't change.

1. so ether_type, if it's false or nil, is going to be replaced by "3", how can that be compatible with the 4-digit ether_type?
2. is 3 the Gateway-to-Gateway protocol?
answer: The number comes from cat /usr/include/linux/if_ether.h | grep ETH_P_ALL, which along with PF_Packet, make up a socket

Also for this:
140     # The AF / PF number for raw sockets.
141     def raw_address_family
142       case RUBY_PLATFORM
143       when /linux/
144         17 # cat /usr/include/bits/socket.h | grep PF_PACKET
145       when /darwin/
146         18 # cat /usr/include/sys/socket.h | grep AF_LINK
147       when /i386-mingw32/ 
148         18 # winsock.h | grep AF_LINK
149       else
150         raise "Unsupported platform #{RUBY_PLATFORM}"
151       end
152     end


Sweet! Found the Windows equivalent of socket.h -- winsock.h!!  I hope it's up to date. So it says that AF_LINK is 18. :D
Victor says: "I googled around, and it seems that AF_LINK won't work on Windows. The header you have is for Winsock 1.1, and all modern systems use Winsock 2.0. MSDN says that Windows removed raw socket support as of Windows XP SP2." This was done for security reasons.

Window's (Winsock/WSA/Windows Socket API) Raw Socket. Raw Socket is a kind of Windows socket (also containing some common choices for domain, type, and protocol), following the format of Berkeley's raw socket.
domain: AF_LINK, same as /darwin/
type: SOCK_RAW, same :D
protocol: hope that 3, eth_p_all would work
:P

commit b458ffaebeabc408c9649c37b9e1951316852ab5
try still. Fixed some Windows socket stuff, found AF_LINK in winsock.h


Administrator@HAOQI-4F34C3203 ~/Desktop/ethernet/spec/ethernet (master)
$ rspec raw_socket_spec.rb
FFFFFF

Failures:

  1) RawSocket mac should have 6 bytes
     Failure/Error: let(:mac) { Ethernet::RawSocket.mac eth_device }
     Errno::EAFNOSUPPORT:
       An address incompatible with the requested protocol was used. - socket(2)

     # c:/Documents and Settings/Administrator/Desktop/ethernet/lib/ethernet/raw
_socket.rb:25:in `initialize'
     # c:/Documents and Settings/Administrator/Desktop/ethernet/lib/ethernet/raw
_socket.rb:25:in `new'
     # c:/Documents and Settings/Administrator/Desktop/ethernet/lib/ethernet/raw
_socket.rb:25:in `socket'
     # c:/Documents and Settings/Administrator/Desktop/ethernet/lib/ethernet/raw
_socket.rb:49:in `mac'
     # ./raw_socket_spec.rb:8:in `block (2 levels) in '
     # ./raw_socket_spec.rb:17:in `block (3 levels) in '

... same stuff

Finished in 0.01562 seconds
6 examples, 6 failures

Failure/Error: let(:mac) { Ethernet::RawSocket.mac eth_device }
     NameError:
       uninitialized constant Module::ANY
     # c:/Documents and Settings/Administrator/Desktop/ethernet/lib/ethernet/raw
_socket.rb:133:in `all_ethernet_protocols'



./Win32/Src/getaddrinfo.c: { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },

Try instead of htons(ETH_P_ALL) , which we have here as 3, do htons(ANY)

commit 6be0d35378b021a8981dfbec4b920317123bc64d
try. switch htons(3) to htons(ANY)

question for Victor:
Do you have any hints of looking for the Windows equivalent of if_ether.h or know what I should put in for ether_type?

Continued from Victor's quote above ... "All solutions seem to revolve around installing some NDIS driver and talking to it. Winpcap seems to be the easiest and most well-maintained library for that."

I need raw socket for an application that i am trying to execute from cygwin in 'Windows XP with SP2' & Vista . How can this be achieved ?
Use a driver that doesn't use the Windows TCP/IP stack, maybe try WinPcap.



====

- Download WinPcap source
-> install NDIS driver
Nice Site

Git Bash Copy Paste

Windows Git Bash how to copy paste / highlight text / select text

Copy:
Long-term solution: Click on Topleft icon > Defaults > Select "QuickEdit Mode" under "Edit Options" > Okay
Then select the text you want to copy. Press Enter


Short-term solution: Click on Topleft icon > Edit > Mark. Press Enter.


Paste:
Press "Insert"

(If the "QuickEdit Mode" is on, Right clicking might work too.)


Credit

Wednesday, April 27, 2011

Making the RubyGem work (bundle & rake install) with Windows - ruby for different platforms!

Ruby file .rb:
Detecting operating systems on Ruby, the backslashes are for regex:
    Linux: /linux/
    Windows: /win32/
    Mac OS: /darwin/
So a ruby file would have these things to distinguish different code for different platforms:
case RUBY_PLATFORM
  when /i386-mingw32/ # OR /win32/ matching Gemfile.lock under PLATFORMS
    require_files :win32
  when /linux/
    require_files :linux
else
    raise "Unsupported platform #{RUBY_PLATFORM}"
end

Gemfile:
Gem Bundler's Gemfile has special syntax (documentation, and examples).

Here is an example to write Windows-only gem:
### windows specific gems ###
 gem 'win32-process', :platforms => [:mswin, :mingw]
 gem 'win32console', :platforms => [:mswin, :mingw]

or 

### windows specific gems ###
platforms :mswin, :mingw do
    gem  'win32console', '1.3.0'
    gem  'wind32-process'
end

The symbols ":mswin" and ":mingw" are special platforms groups.
gem "rspec", :group => :test
gem "wirble", :groups => [:development, :test]
Unfortunately, there is no ":linux", so it'll be a non-platform group, which means the command should be "bundle install --without linux" when running on Windows.

Yay! Can:
bundle install --without linux
rake install

commit 8b8573dcc87e673cca042e2d68569fffd586e872
try if Windows rake will work after making system/getifaddrs only for linux


====
Next step:
- downgrade to 1.8.7 ruby
- make sockets work  (google, more wireshark digging)
- How to list devices, look at: fad-win32.c.
(change :linux to :ruby to avoid "--without linux" on Windows, i.e. does :ruby work as platform thingy not just a group?)
===
IRC: freenode ruby chat
#RubyOnRails
#bundler
#ruby-lang

==
This pipe server Windomit ws gem be helpful?

Wednesday, March 30, 2011

Set up Windows, Figure out how to list network devices in Linux

On Monday, I met with Victor and leaned that there are 2 different ways to write the API. I'm going to use Victor's ether_shell way.

Made a new to-do list:

I. Windows set things up
II. Linux: Find how to list all the network card names
III. to-do 2/4: Windows/MacOS: Find code in Wireshark that a) communicates to the ethernet, b) gets the MAC addresses in those operating systems
IV. to-do 3/4: Read POSIX socket API document


I. Windows: set things up to test on it
  1. Install Windows XP virtual machine on my computer's VM Player (victor gave me its iso)
  2. Install Ruby http://rubyinstaller.org/
    • check "add ruby executables to your PATH"
    • check "associate .rb and .rbw files with this ruby installation"
  3. Install Git http://code.google.com/p/msysgit/downloads/list
    • select "rub git from the Windows command prompt"
    • select "checkout windows-style, commit unix-style line endings"
  4. Install wireshark
    • Ignore the popup that's about enabling promiscuous mode
  5. Download my github ethernet project (that is currently is a copy/paste of Victor's ether_shell), I just want to see if the rspec can run.
    • No. When I ran rspec ethernet_spec.rb I got:
      sh.exe": rspec: command not found
      So I did, like on Linux, gem install rspec, and then rspec worked!
  6. I tried to replicate pinging Wireshark based on this blog entry, but at the rake install step, I got an error as expected, since I haven't written anything that makes things work on Windows yet!
    rake aborted!
    undefined method `write' for #<Syck::Emitter:0x11efad0>
    c:/Ruby192/lib/ruby/1.9.1/psych/visitors/emitter.rb:17:in `end_document'
    c:/Ruby192/lib/ruby/1.9.1/psych/visitors/emitter.rb:17:in `visit_Psych_Nodes_Document'
    c:/Ruby192/lib/ruby/1.9.1/psych/visitors/visitor.rb:10:in `accept'
    c:/Ruby192/lib/ruby/1.9.1/psych/visitors/emitter.rb:10:in `block in visit_Psych_Nodes_Stream'
    c:/Ruby192/lib/ruby/1.9.1/psych/visitors/emitter.rb:10:in `each'
    c:/Ruby192/lib/ruby/1.9.1/psych/visitors/emitter.rb:10:in `visit_Psych_Nodes_Stream'
    c:/Ruby192/lib/ruby/1.9.1/psych/visitors/visitor.rb:11:in `accept'
    c:/Ruby192/lib/ruby/1.9.1/psych/nodes/node.rb:36:in `to_yaml'
    c:/Ruby192/lib/ruby/1.9.1/psych.rb:166:in `dump'
    c:/Ruby192/lib/ruby/1.9.1/psych/core_ext.rb:13:in `psych_to_yaml'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/specification.rb:706:in `node_export'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/specification.rb:706:in `add'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/specification.rb:706:in `encode_with'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/specification.rb:728:in `block (2 levels) in to_yaml'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/specification.rb:727:in `map'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/specification.rb:727:in `block in to_yaml'
    c:/Ruby192/lib/ruby/1.9.1/syck.rb:401:in `call'
    c:/Ruby192/lib/ruby/1.9.1/syck.rb:401:in `emit'
    c:/Ruby192/lib/ruby/1.9.1/syck.rb:401:in `quick_emit'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/specification.rb:726:in `to_yaml'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/builder.rb:78:in `block (2 levels) in write_package'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/package/tar_output.rb:73:in `block (3 levels) in add_gem_contents'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/package/tar_writer.rb:83:in `new'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/package/tar_output.rb:67:in `block (2 levels) in add_gem_contents'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/package/tar_output.rb:65:in `wrap'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/package/tar_output.rb:65:in `block in add_gem_contents'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/package/tar_writer.rb:113:in `add_file'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/package/tar_output.rb:63:in `add_gem_contents'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/package/tar_output.rb:31:in `open'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/package.rb:68:in `open'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/builder.rb:77:in `block in write_package'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/builder.rb:76:in `open'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/builder.rb:76:in `write_package'
    c:/Ruby192/lib/ruby/site_ruby/1.9.1/rubygems/builder.rb:39:in `build'
    c:/Ruby192/lib/ruby/gems/1.9.1/gems/jeweler-1.5.2/lib/jeweler/commands/build_gem.rb:16:in `run'
    c:/Ruby192/lib/ruby/gems/1.9.1/gems/jeweler-1.5.2/lib/jeweler.rb:87:in `build_gem'
    c:/Ruby192/lib/ruby/gems/1.9.1/gems/jeweler-1.5.2/lib/jeweler/tasks.rb:84:in `block in define'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:634:in `call'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:634:in `block in execute'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:629:in `each'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:629:in `execute'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:595:in `block in invoke_with_call_chain'
    c:/Ruby192/lib/ruby/1.9.1/monitor.rb:201:in `mon_synchronize'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:588:in `invoke_with_call_chain'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:605:in `block in invoke_prerequisites'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:602:in `each'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:602:in `invoke_prerequisites'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:594:in `block in invoke_with_call_chain'
    c:/Ruby192/lib/ruby/1.9.1/monitor.rb:201:in `mon_synchronize'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:588:in `invoke_with_call_chain'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:581:in `invoke'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:2041:in `invoke_task'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:2019:in `block (2 levels) in top_level'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:2019:in `each'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:2019:in `block in top_level'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:2058:in `standard_exception_handling'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:2013:in `top_level'
    c:/Ruby192/lib/ruby/1.9.1/rake.rb:1992:in `run'
    c:/Ruby192/bin/rake:31:in `<main>'
  7. I also got the DevKit from http://rubyinstaller.org/downloads, following these directions to set up: https://github.com/oneclick/rubyinstaller/wiki/Development-Kit (I used this to "gem install rcov --platform=ruby", but it was not necessary since the next step covers it.)
  8. bundle install which results to installing a bunch of gems and saying "Your bundle is complete!"
  9. rake install
    Successfully built RubyGem
    ...
    ...
    ERROR: Error installing ./pkg/ethernet-0.0.0.gem:
                   ERROR: Failed to build gem native extension.

                   c:/Ruby192/bin/ruby.exe extconf.rb
    checking for a bunch of stuff ...
    This is because I haven't written the Windows parts of the gem yet! :D
  10. Continued in this blog
  11. to-do 4/4: read about MSDN

II. Linux: Find how to list all the network card names
I need to look into the system calls behind ifconfig to see how it lists all the network card device names.

  • http://linux.die.net/man/2/syscalls has system calls
  • I tried strace ifconfig 2> ifctrace.txt
  • Google for "sourcecode ifconfig", found a bsd version to-do 1/4: read it to figure out how linux list devices!