punchd/ip_packet.nim

88 lines
3.3 KiB
Nim
Raw Normal View History

2020-07-10 19:36:41 +02:00
from nativesockets import ntohs, ntohl, htons, htonl
from net import IpAddress, IpAddressFamily, Port, `$`
2020-05-21 01:17:37 +02:00
from posix import InAddr, inet_ntoa
type
Ether_header {.importc: "struct ether_header", pure, final,
header: "<netinet/if_ether.h>".} = object
ether_dhost: array[6, uint8]
ether_shost: array[6, uint8]
2020-05-21 01:17:37 +02:00
ether_type: cushort
Ip {.importc: "struct ip", pure, final,
header: "<netinet/ip.h>".} = object
when cpuEndian == littleEndian:
ip_hl {.bitsize:4.}: uint # header length
ip_v {.bitsize:4.}: uint # version
2020-05-21 01:17:37 +02:00
else:
ip_v {.bitsize:4.}: uint # version
ip_hl {.bitsize:4.}: uint # header length
ip_tos: uint8 # type of service
ip_len: cushort # total length
2020-05-21 01:17:37 +02:00
ip_id: cushort # identification
ip_off: cushort # fragment offset field
ip_ttl: uint8 # time to live
2020-05-21 01:17:37 +02:00
ip_p: cuchar # protocol
ip_sum: cushort # checksum
ip_src: InAddr # source address
ip_dst: InAddr # destination address
Tcphdr {.importc: "struct tcphdr", pure, final,
header: "<netinet/tcp.h>".} = object
th_sport: uint16 # source port
th_dport: uint16 # destination port
2020-05-21 01:17:37 +02:00
th_seq: uint32 # sequence number
th_ack: uint32 # ackkowledgment number
when cpuEndian == littleEndian:
th_x2 {.bitsize:4.}: uint8 # (unused)
th_off {.bitsize:4.}: uint8 # data offset
2020-05-21 01:17:37 +02:00
else:
th_off {.bitsize:4.}: uint8 # (unused)
th_x2 {.bitsize:4.}: uint8 # data offset
th_flags: uint8 # flags
th_win: uint16 # window
th_sum: uint16 # checksum
th_urp: uint16 # urgent pointer
2020-05-21 01:17:37 +02:00
Protocol* = enum
tcp
other
2020-07-09 21:10:25 +02:00
IpPacket* = object
2020-05-21 01:17:37 +02:00
case protocol*: Protocol
of tcp:
2020-07-10 19:36:41 +02:00
tcpIpSrc*: IpAddress
tcpIpDst*: IpAddress
2020-05-21 01:17:37 +02:00
tcpPortSrc*: Port
tcpPortDst*: Port
tcpSeqNumber*: uint32
else:
discard
var
ETHERTYPE_IP {.importc: "ETHERTYPE_IP", header: "<netinet/if_ether.h>".}: cushort
IPPROTO_TCP {.importc: "IPPROTO_TCP", header: "<netinet/in.h>".}: cint
2020-07-09 21:10:25 +02:00
proc parseEthernetPacket*(input: string): IpPacket =
let etherHeader = cast[ptr Ether_header](input.cstring)
2020-05-21 01:17:37 +02:00
if ntohs(etherHeader.ether_type) == ETHERTYPE_IP:
2020-07-09 21:10:25 +02:00
let ipHeader = cast[ptr Ip](cast[int](input.cstring) + sizeof(Ether_header))
2020-07-10 19:36:41 +02:00
let ipSrcScalar = ntohl(ipHeader.ip_src.s_addr)
let ipDstScalar = ntohl(ipHeader.ip_dst.s_addr)
let ipSrc = IpAddress(family: Ipv4,
address_v4: cast[array[4, uint8]](ipSrcScalar))
let ipDst = IpAddress(family: Ipv4,
address_v4: cast[array[4, uint8]](ipDstScalar))
2020-05-21 01:17:37 +02:00
if ipHeader.ip_p.int == IPPROTO_TCP:
let tcpHeader = cast[ptr Tcphdr](cast[int](ipHeader) + ipHeader.ip_hl.int * 4)
2020-07-09 21:10:25 +02:00
result = IpPacket(protocol: tcp,
2020-07-10 19:36:41 +02:00
tcpIpSrc: ipSrc,
tcpIpDst: ipDst,
tcpPortSrc: Port(ntohs(tcpHeader.th_sport)),
tcpPortDst: Port(ntohs(tcpHeader.th_dport)),
tcpSeqNumber: ntohl(tcpHeader.th_seq))
2020-05-21 01:17:37 +02:00
else:
2020-07-09 21:10:25 +02:00
result = IpPacket(protocol: other)
2020-05-21 01:17:37 +02:00
else:
2020-07-09 21:10:25 +02:00
result = IpPacket(protocol: other)