Skip to content

Latest commit

 

History

History
367 lines (305 loc) · 9.28 KB

ruby-socket.md

File metadata and controls

367 lines (305 loc) · 9.28 KB

Ruby Socket

Lightweight Introduction

Ruby Socket Class Hierarchy

To know the socket hierarchy in ruby here a simple tree explains it.

IO                              # The basis for all input and output in Ruby
└── BasicSocket                 # Abstract base class for all socket classes
    ├── IPSocket                # Super class for protocols using the Internet Protocol (AF_INET)
    │   ├── TCPSocket           # Class for Transmission Control Protocol (TCP) sockets
    │   │   ├── SOCKSSocket     # Helper class for building TCP socket servers applications
    │   │   └── TCPServer       # Helper class for building TCP socket servers
    │   └── UDPSocket           # Class for User Datagram Protocol (UDP) sockets
    ├── Socket                  # Base socket class that mimics that BSD Sockets API. It provides more operating system specific functionality
    └── UNIXSocket              # Class providing IPC using the UNIX domain protocol (AF_UNIX)
        └── UNIXServer          # Helper class for building UNIX domain protocol socket servers

I'll verbosely mention some of Socket::Constants here since I didn't find an obvious reference listing it except Programming Ruby1.9 The Pragmatic Programmers' Guide; Otherwise you've to ri Socket::Constants from command line which is a good way to get the description of each constant.

Socket Types

  • SOCK_RAW
  • SOCK_PACKET
  • SOCK_STREAM
  • SOCK_DRAM
  • SOCK_RDM
  • SOCK_SEQPACKET

Address Families(Socket Domains)

  • AF_APPLETALK
  • AF_ATM
  • AF_AX25
  • AF_CCITT
  • AF_CHAOS
  • AF_CNT
  • AF_COIP
  • AF_DATAKIT
  • AF_DEC
  • AF_DLI
  • AF_E164
  • AF_ECMA
  • AF_HYLINK
  • AF_IMPLINK
  • AF_INET(IPv4)
  • AF_INET6(IPv6)
  • AF_IPX
  • AF_ISDN
  • AF_ISO
  • AF_LAT
  • AF_LINK
  • AF_LOCAL(UNIX)
  • AF_MAX
  • AF_NATM
  • AF_NDRV
  • AF_NETBIOS
  • AF_NETGRAPH
  • AF_NS
  • AF_OSI
  • AF_PACKET
  • AF_PPP
  • AF_PUP
  • AF_ROUTE
  • AF_SIP
  • AF_SNA
  • AF_SYSTEM
  • AF_UNIX
  • AF_UNSPEC

Socket Protocol

  • IPPROTO_SCTP
  • IPPROTO_TCP
  • IPPROTO_UDP

Protocol Families

  • PF_APPLETALK
  • PF_ATM
  • PF_AX25
  • PF_CCITT
  • PF_CHAOS
  • PF_CNT
  • PF_COIP
  • PF_DATAKIT
  • PF_DEC
  • PF_DLI
  • PF_ECMA
  • PF_HYLINK
  • PF_IMPLINK
  • PF_INET
  • PF_INET6
  • PF_IPX
  • PF_ISDN
  • PF_ISO
  • PF_KEY
  • PF_LAT
  • PF_LINK
  • PF_LOCAL
  • PF_MAX
  • PF_NATM
  • PF_NDRV
  • PF_NETBIOS
  • PF_NETGRAPH
  • PF_NS
  • PF_OSI
  • PF_PACKET
  • PF_PIP
  • PF_PPP
  • PF_PUP
  • PF_ROUTE
  • PF_RTIP
  • PF_SIP
  • PF_SNA
  • PF_SYSTEM
  • PF_UNIX
  • PF_UNSPEC
  • PF_XTP

Socket options

  • SO_ACCEPTCONN
  • SO_ACCEPTFILTER
  • SO_ALLZONES
  • SO_ATTACH_FILTER
  • SO_BINDTODEVICE
  • SO_BINTIME
  • SO_BROADCAST
  • SO_DEBUG
  • SO_DETACH_FILTER
  • SO_DONTROUTE
  • SO_DONTTRUNC
  • SO_ERROR
  • SO_KEEPALIVE
  • SO_LINGER
  • SO_MAC_EXEMPT
  • SO_NKE
  • SO_NOSIGPIPE
  • SO_NO_CHECK
  • SO_NREAD
  • SO_OOBINLINE
  • SO_PASSCRED
  • SO_PEERCRED
  • SO_PEERNAME
  • SO_PRIORITY
  • SO_RCVBUF
  • SO_RCVLOWAT
  • SO_RCVTIMEO
  • SO_RECVUCRED
  • SO_REUSEADDR
  • SO_REUSEPORT
  • SO_SECURITY_AUTHENTICATION
  • SO_SECURITY_ENCRYPTION_NETWORK
  • SO_SECURITY_ENCRYPTION_TRANSPORT
  • SO_SNDBUF
  • SO_SNDLOWAT
  • SO_SNDTIMEO
  • SO_TIMESTAMP
  • SO_TIMESTAMPNS
  • SO_TYPE
  • SO_USELOOPBACK
  • SO_WANTMORE
  • SO_WANTOOBFLAG

Creating Socket Template

Socket.new(domain, socktype [, protocol])

domain(Address\/Protocol Families): like AF_INET, PF_PACKET, etc

socktype: like SOCK_RAW, SOCK_STREAM

protocol: by default, it's 0m it should be a protocol defined (we'll manipulate that later)

TCP Socket

Server\/Client life cycle

            Client        Server
              |             |                  
   socket     +             +      socket
              |             |
   connect    +--------,    +      bind
              |         |   |
   write ,--> +------,  |   +      listen
         |    |      |  |   |
   read  `----+ <--, |  `-> +      accept
              |    | |      |
   close      +--, | `----> + <--, read <--,
                 | |        |    |         |
                 | `--------+----' write   ٨
                 |                         |
                 `----->------>------->----`

General Socket usage

Get List of local IPaddreses

require 'socket'
Socket.ip_address_list

Get Hostname

Socket.gethostname

TCP Server

Here we'll represent an absolute TCP server. This server will access connect from one client and send a message to it once connected then close the client and server connection

require 'socket'

server = TCPServer.new('0.0.0.0', 9911) # Server, binds/listens all interfaces on port 9911
client = server.accept                  # Wait for client to connect
rhost  = client.peeraddr.last           # peeraddr, returns remote [address_family, port, hostname, numeric_address(ip)]
client.puts "Hi TCP Client! #{rhost}"   # Send a message to the client once it connect
client.gets.chomp                       # Read incoming message from client
client.close                            # Close the client's connection
server.close                            # Close the TCP Server

Note: if you want to list on unused and random port, set to port 0, ruby will find vacancy port then use it. ex.

require 'socket'
server = TCPServer.new('0.0.0.0', 0)
server.addr[1]    # Shows the picked port

TCP Client

require 'socket'

client = TCPSocket.new('127.0.0.1', 9911)   # Client, connects to server on port 9911
rhost  = client.peeraddr.last               # Get the remote server's IP address 
client.gets.chomp
client.puts "Hi, TCP Server #{rhost}"
client.close

You can put timeout/time interval for current connection in-case the server's response get delayed and the socket is still open.

timeval = [3, 0].pack("l_2")        # Time interval 3 seconds 
client.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, timeval      # Set socket receiving time interval 
client.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, timeval      # Set socket sending time interval
client.getsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO).inspect      # Optional, Check if socket option has been set
client.getsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO).inspect      # Optional, Check if socket option has been set

There are some alternatives for puts and gets methods.You can see the difference and its classes using method method in Pry interpreter console

>> s = TCPSocket.new('0.0.0.0', 9911)
=> #<TCPSocket:fd 11>
>> s.method :puts
=> #<Method: TCPSocket(IO)#puts>
>> s.method :write
=> #<Method: TCPSocket(IO)#write>
>> s.method :send
=> #<Method: TCPSocket(BasicSocket)#send>
>> s = TCPSocket.new('0.0.0.0', 9911)
=> #<TCPSocket:fd 11>
>> s.method :gets
=> #<Method: TCPSocket(IO)#gets>
>> s.method :read
=> #<Method: TCPSocket(IO)#read>
>> s.method :recv
=> #<Method: TCPSocket(BasicSocket)#recv>

UDP Socket

UDP Server

require 'socket'

server = UDPSocket.new                                  # Start UDP socket
server.bind('0.0.0.0', 9911)                            # Bind all interfaces to port 9911
mesg, addr = server.recvfrom(1024)                      # Receive 1024 bytes of the message and the sender IP
server puts "Hi, UDP Client #{addr}", addr[3], addr[1]  # Send a message to the client 
server.recv(1024)                                       # Receive 1024 bytes of the message

UDP Client

require 'socket'
client = UDPSocket.new
client.connect('localhost', 9911)       # Connect to server on port 991
client.puts "Hi, UDP Server!", 0        # Send message 
server.recv(1024)                       # Receive 1024 bytes of the server message

There alternative for sending and receiving too, figure it out, RubyDoc.

GServer

GServer standard library implements a generic server, featuring thread pool management, simple logging, and multi-server management. Any kind of application-level server can be implemented using this class:

  • It accepts multiple simultaneous connections from clients
  • Several services (i.e. one service per TCP port)
    • can be run simultaneously,
    • can be stopped at any time through the class method GServer.stop(port)
  • All the threading issues are handled
  • All events are optionally logged
  • Very basic GServer
require 'gserver'

class HelloServer < GServer                 # Inherit GServer class
  def serve(io)
    io.puts("What's your name?")
    line = io.gets.chomp
    io.puts "Hi, #{line}!"
    self.stop if io.gets =~ /shutdown/      # Stop the server if you get shutdown string
  end
end

server = HelloServer.new(1234, '0.0.0.0')   # Start the server on port 1234
server.audit = true     # Enable logging
server.start            # Start the service 
server.join

Port knocking

Simple port knocker using the socket standard library.

require 'socket'

ports = [42, 1337, 10420, 6969, 63000]

ports.each do |port|
  puts "[+] Port: #{port}"
  sleep 1
  begin
    s = TCPSocket.new '10.10.70.53', port
    s.close
  rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
    next
  end
end

Ref.: