nstack/tcp_device.rb
2021-05-16 11:05:27 -05:00

65 lines
1.5 KiB
Ruby

# frozen_string_literal: true
require_relative 'proto_type'
require_relative 'interface_list'
require_relative 'ipv4_device'
require 'packetfu'
# Handles functions common to all TCP sockets
module TCPLayer
@sockets = {}
@packets = []
def self.initialize
IPv4Layer.register_handler('0.0.0.0', ProtoType::IPv4::TCP, self)
end
def self.got_packet(packet)
socket = @sockets[[packet.ip_daddr, packet.tcp_dport]]
if socket
socket.got_packet(packet)
else
send_rst_to(packet)
end
end
def self.send_packet(packet)
IPv4Layer.send_packet(packet)
end
def self.register_socket(ip, port, socket)
raise Errno::EADDRINUSE, "bind(2) for \"#{ip}\" port #{port}" if @sockets[[ip, port]]
@sockets[[ip, port]] = socket
end
def self.delete_socket(ip, port)
@sockets.delete [ip, port]
end
def self.close_all
@sockets.each_value { _1.wait_till_closed }
end
def self.packet_seq_len(packet)
flags = packet.tcp_flags
len = packet.payload.length
len += 1 if flags.syn == 1 || flags.fin == 1
len
end
# rubocop: disable Metrics/AbcSize
def self.send_rst_to(packet)
pkt = PacketFu::TCPPacket.new
pkt.ip_daddr = packet.ip_saddr
pkt.tcp_sport = packet.tcp_dport
pkt.tcp_dport = packet.tcp_sport
pkt.tcp_flags = PacketFu::TcpFlags.new({ rst: true, ack: true })
pkt.tcp_seq = packet.tcp_ack
pkt.tcp_ack = packet.tcp_seq + packet_seq_len(packet)
send_packet(pkt)
end
# rubocop: enable Metrics/AbcSize
end