Skip to content

Instantly share code, notes, and snippets.

@noraj
Last active March 2, 2023 22:29
Show Gist options
  • Save noraj/d6f7ca3a73aeefeb09299d3299cfea6f to your computer and use it in GitHub Desktop.
Save noraj/d6f7ca3a73aeefeb09299d3299cfea6f to your computer and use it in GitHub Desktop.
netstat -ta4 or ss -ta4 equivalent in Ruby and Crystal
require 'etc'
TCP_STATES = { # /usr/src/linux/include/net/tcp_states.h
'00': 'UNKNOWN',
'FF': 'UNKNOWN',
'01': 'ESTABLISHED',
'02': 'SYN_SENT',
'03': 'SYN_RECV',
'04': 'FIN_WAIT1',
'05': 'FIN_WAIT2',
'06': 'TIME_WAIT',
'07': 'CLOSE',
'08': 'CLOSE_WAIT',
'09': 'LAST_ACK',
'0A': 'LISTEN',
'0B': 'CLOSING',
'0C': 'NEW_SYN_RECV'
}
def decode_addr(addr)
ip, port = addr.split(':')
ip = ip.scan(/.{2}/).map{|x|x.hex.to_s}.reverse.join('.')
port = port.hex.to_s
"#{ip}:#{port}"
end
puts 'local address'.ljust(22) + 'remote address'.ljust(22) + 'state'.ljust(12) + 'username (uid)'
File.readlines('/proc/net/tcp').each_with_index do |line, i|
entry = line.split(' ')
unless i == 0 # skip headers
laddr = decode_addr(entry[1])
raddr = decode_addr(entry[2])
state = TCP_STATES[entry[3].to_sym]
uid = entry[7]
uname = Etc.getpwuid(uid.to_i).name
puts "#{laddr.ljust(22)}#{raddr.ljust(22)}#{state.ljust(12)}#{uname} (#{uid})"
end
end
$ ruby mini-netstat.rb
local address         remote address        state       username (uid)
0.0.0.0:8060          0.0.0.0:0             LISTEN      root (0)
127.0.0.1:9121        0.0.0.0:0             LISTEN      gitlab-redis (997)
127.0.0.1:9090        0.0.0.0:0             LISTEN      gitlab-prometheus (992)
127.0.0.1:9187        0.0.0.0:0             LISTEN      gitlab-psql (996)
127.0.0.1:9093        0.0.0.0:0             LISTEN      gitlab-prometheus (992)
127.0.0.1:9229        0.0.0.0:0             LISTEN      git (998)
127.0.0.1:8080        0.0.0.0:0             LISTEN      git (998)
127.0.0.1:9168        0.0.0.0:0             LISTEN      git (998)
0.0.0.0:80            0.0.0.0:0             LISTEN      root (0)
127.0.0.1:8082        0.0.0.0:0             LISTEN      git (998)
127.0.0.1:9236        0.0.0.0:0             LISTEN      git (998)
0.0.0.0:22            0.0.0.0:0             LISTEN      root (0)
127.0.0.1:8080        127.0.0.1:37976       TIME_WAIT   root (0)
127.0.0.1:57568       127.0.0.1:9090        ESTABLISHED gitlab-prometheus (992)
127.0.0.1:57562       127.0.0.1:9090        ESTABLISHED gitlab-prometheus (992)
127.0.0.1:58602       127.0.0.1:8082        ESTABLISHED gitlab-prometheus (992)
127.0.0.1:56314       127.0.0.1:9229        ESTABLISHED gitlab-prometheus (992)
127.0.0.1:8080        127.0.0.1:37978       TIME_WAIT   root (0)
127.0.0.1:36808       127.0.0.1:9187        ESTABLISHED gitlab-prometheus (992)
127.0.0.1:55434       127.0.0.1:9168        ESTABLISHED gitlab-prometheus (992)
172.17.0.2:33956      10.10.14.135:4444     ESTABLISHED git (998)
127.0.0.1:8082        127.0.0.1:58602       ESTABLISHED git (998)
127.0.0.1:51426       127.0.0.1:80          TIME_WAIT   root (0)
127.0.0.1:9229        127.0.0.1:56314       ESTABLISHED git (998)
127.0.0.1:9090        127.0.0.1:57562       ESTABLISHED gitlab-prometheus (992)
127.0.0.1:9168        127.0.0.1:55420       ESTABLISHED git (998)
127.0.0.1:9187        127.0.0.1:36808       ESTABLISHED gitlab-psql (996)
127.0.0.1:8080        127.0.0.1:37984       TIME_WAIT   root (0)
127.0.0.1:55420       127.0.0.1:9168        ESTABLISHED gitlab-prometheus (992)
127.0.0.1:9168        127.0.0.1:55436       ESTABLISHED git (998)
127.0.0.1:9121        127.0.0.1:46208       ESTABLISHED gitlab-redis (997)
127.0.0.1:55436       127.0.0.1:9168        ESTABLISHED gitlab-prometheus (992)
127.0.0.1:8060        127.0.0.1:56772       ESTABLISHED gitlab-www (999)
127.0.0.1:8080        127.0.0.1:37982       TIME_WAIT   root (0)
127.0.0.1:46208       127.0.0.1:9121        ESTABLISHED gitlab-prometheus (992)
172.17.0.2:60588      10.10.14.179:4444     ESTABLISHED git (998)
127.0.0.1:9090        127.0.0.1:57568       ESTABLISHED gitlab-prometheus (992)
127.0.0.1:9236        127.0.0.1:32882       ESTABLISHED git (998)
127.0.0.1:32882       127.0.0.1:9236        ESTABLISHED gitlab-prometheus (992)
127.0.0.1:56772       127.0.0.1:8060        ESTABLISHED gitlab-prometheus (992)
127.0.0.1:9168        127.0.0.1:55434       ESTABLISHED git (998)
TCP_STATES = { # /usr/src/linux/include/net/tcp_states.h
"00" => "UNKNOWN",
"FF" => "UNKNOWN",
"01" => "ESTABLISHED",
"02" => "SYN_SENT",
"03" => "SYN_RECV",
"04" => "FIN_WAIT1",
"05" => "FIN_WAIT2",
"06" => "TIME_WAIT",
"07" => "CLOSE",
"08" => "CLOSE_WAIT",
"09" => "LAST_ACK",
"0A" => "LISTEN",
"0B" => "CLOSING",
"0C" => "NEW_SYN_RECV"
}
module Etc
def self.getpwuid(uid)
File.read_lines("/etc/passwd").each_with_index do |line, i|
entry = line.split(":", remove_empty: false)
return entry[0] if entry[2] == uid
end
end
end
def decode_addr(addr)
ip, port = addr.split(":", remove_empty: true)
ip = ip.scan(/.{2}/).reverse_each.join('.'){ |x| x[0].to_i(16) }
port = port.to_i(16).to_s
"#{ip}:#{port}"
end
puts "local address".ljust(22) + "remote address".ljust(22) + "state".ljust(12) + "username (uid)"
File.read_lines("/proc/net/tcp").each_with_index do |line, i|
entry = line.split(" ", remove_empty: true)
unless i == 0 # skip headers
laddr = decode_addr(entry[1])
raddr = decode_addr(entry[2])
state = TCP_STATES[entry[3]]
uid = entry[7]
uname = Etc.getpwuid(uid)
puts "#{laddr.ljust(22)}#{raddr.ljust(22)}#{state.ljust(12)}#{uname} (#{uid})"
end
end

Ruby to Crystal conversion required the following changes:

  • replaced File.readlines with File.read_lines
  • replaced String.hex with String.to_i(16)
  • Regex return Regex::MatchData and not a string you need to access a [0] like for capture groups
  • String.to_sym doesn't exist in Crystal so changed key from symbol to string
  • added remove_empty: true to split() as it's not done by default when a separator is provided
  • replaced Etc.getpwuid witch custom code since the etc module is not implemented in Crystal
  • changed all single quotes to doubles quotes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment