diff options
| author | Drahflow <drahflow@gmx.de> | 2013-09-02 11:27:01 +0200 |
|---|---|---|
| committer | Drahflow <drahflow@gmx.de> | 2013-09-02 11:27:01 +0200 |
| commit | 92b6155a1c3a209936dddebb8bf3372ebee78f94 (patch) | |
| tree | 8680757163dc8dbbea513b60f27945ec9c021af9 /elymas/lib/net | |
| parent | dd98844bd4968664f9dd7be996df596873733ecd (diff) | |
I CAN HAZ TCP/IP CONNECTION!
Very crappy HTTP client:
"drahflow.name:80" net .tcp .connect "+" via
"GET / HTTP/1.0\n\n" +writeall
4096 +read dump
Diffstat (limited to 'elymas/lib/net')
| -rw-r--r-- | elymas/lib/net/dns.ey | 138 | ||||
| -rw-r--r-- | elymas/lib/net/tcp.ey | 37 | ||||
| -rw-r--r-- | elymas/lib/net/udp.ey | 36 |
3 files changed, 211 insertions, 0 deletions
diff --git a/elymas/lib/net/dns.ey b/elymas/lib/net/dns.ey new file mode 100644 index 0000000..b4a5dbe --- /dev/null +++ b/elymas/lib/net/dns.ey @@ -0,0 +1,138 @@ +# Provide nice ways to do DNS resolution +# Spec: http://www.faqs.org/rfcs/rfc1035.html + +< +# Uncomment to enable function ("deffd") tracing for this scope +# { +# -010 { " executing" cat dump }_ -01 ; -01 =*: +# }" /deffd deffd + + bin .scan "->" via + bin .print "<-" via + bin .produce "<=" via + sys .linux "+" via + + # 0 -> ascii ip address + # 0 <- ipv4 address as un32 + { [ -01 "^(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)$" regex not { "not an IPv4 address" die } rep ] + [ -01 txt .consume .|u each ] # FIXME employ typed functions and auto-map + reverse str .fromArray + } /parseIpv4 deffd + + # 0 -> hostname + # 0 <- ipv4 address as un32 + { ==host + ensureResolvConf + resolvConf .nameserver parseIpv4 53 net .udp .sockaddrIpv4 + +AFINET +SOCKDGRAM +IPPROTOUDP +socket _ ==s # TODO: error handling + -01 +connect -- # TODO: error handling + + s + host buildDnsQueryMessage + _ len + +write -- # TODO: error handling + + 1024 str .alloc ==buf + + s + buf + _ len + +read # TODO: error handling + buf str .inplacePrefix =buf + + buf + ->un16 ==id # expected to be zero + ->u16 2 math .base ==bitfields + ->un16 ==qdCount + ->un16 ==anCount + ->un16 ==nsCount # expected to be zero + ->un16 ==arCount # expected to be zero + + qdCount { + ->u8 ==labelLength + { labelLength } { + labelLength 64 ge { + "unexpected compression pointer in DNS reply" die + } { + labelLength -01 str .postfix + ->u8 =labelLength + } ? * + } loop + ->un16 ==qType + ->un16 ==qClass + } rep + + # _ |dump each + + anCount { + ->u8 ==labelLength + { labelLength } { + labelLength 64 ge { + ->u8 labelLength 63 band 256 mul add ==pointerTarget # TODO actually care for pointer target + 0 =labelLength + } { + labelLength -01 str .postfix + ->u8 =labelLength + } ? * + } loop + + ->un16 1 eq not { "Answer type field was not 'A'" die } rep + ->un16 1 eq not { "Answer class field was not 'INET'" die } rep + ->un32 -- # _ ==ttl "TTL: " dump dump + ->un16 4 eq not { "Answer data length was not 4" die } rep + 4 -01 str .inplacePrefix # 4 byte IP data to be returned + } { + "Answer did not contain any answer data" die + } ? * + } /resolveIpv4 deffd + + # 0 -> hostname + # 0 <- dns query message + { ==host + 0 <=un16 # id + [ 1 0 0 0 0 0 0 0 ] 2 math .unbase <-u8 # QR Opcode*4 AA TC RD + [ 0 0 0 0 0 0 0 0 ] 2 math .unbase <-u8 # RA Z*3 RCODE*4 + 1 <-un16 # qdcount + 0 <-un16 # ancount + 0 <-un16 # nscount + 0 <-un16 # arcount + ==query + + host { "^([^.]+)\\.?(.*)" regex } { + makeLabel query -01 cat =query + } loop + + query + "\0" cat + + 1 <-un16 # "A" query + 1 <-un16 # "Internet" QCLASS + } /buildDnsQueryMessage deffd + + # 0 -> string + # 0 <- string with u8 length prepended + { _ len <=u8 -01 cat } /makeLabel deffd + + # 0 -> dns message + # 0 <- dns message with tcp transport header prepended + { _ len <=u16 -01 cat } /prepareTcpMessage deffd + + < + 0 ==?loaded + { defv }' /put deffd + > /resolvConf defvd + + # ensure resolv.conf is parsed + { + resolvConf .loaded not { + { [ + { _ "^[ ]*nameserver[ ]+(.*)" regex } { /nameserver resolvConf .put } + ] conds -- } + "/etc/resolv.conf" sys .file ":" via :open :eachLine :close + + 1 /loaded resolvConf .put + } rep + } /ensureResolvConf deffd +> /dns net .defv + +# vim: syn=elymas diff --git a/elymas/lib/net/tcp.ey b/elymas/lib/net/tcp.ey new file mode 100644 index 0000000..dc77515 --- /dev/null +++ b/elymas/lib/net/tcp.ey @@ -0,0 +1,37 @@ +# Provide nice ways to do TCP/IP networking + +< + bin .scan "->" via + bin .print "<-" via + bin .produce "<=" via + sys .linux "+" via + + # 0 -> port + # 1 -> host (as network byte ordered string) + # 0 <- string representing the sockaddr_in + { ==port ==host + +AFINET <=u16 + port <-un16 + host cat + 0 <-un64 + } /sockaddrIpv4 deffd + + # 0 -> "host:port" + # 0 <- connected socket fd + { "^([^:]+):(\\d+)$" regex not { "host:port expected" die } rep + net .dns .resolveIpv4 + -01 txt .consume .u + sockaddrIpv4 + +AFINET +SOCKSTREAM +IPPROTOTCP +socket _ ==s # TODO: error handling + -01 +connect -- # TODO: error handling + s + } /connectFd deffd + + # 0 -> "host:port" + # 0 <- connected socket as file + { + connectFd sys .fdToFile + } /connect deffd +> /tcp net .defv + +# vim: syn=elymas diff --git a/elymas/lib/net/udp.ey b/elymas/lib/net/udp.ey new file mode 100644 index 0000000..5260d5c --- /dev/null +++ b/elymas/lib/net/udp.ey @@ -0,0 +1,36 @@ +# Provide nice ways to do TCP/IP networking + +< + bin .scan "->" via + bin .print "<-" via + bin .produce "<=" via + sys .linux "+" via + + # 0 -> port + # 1 -> host (as network byte ordered string) + # 0 <- string representing the sockaddr_in + { ==port ==host + +AFINET <=u16 + port <-un16 + host cat + 0 <-un64 + } /sockaddrIpv4 deffd + + # 0 -> "host:port" + # 0 <- connected socket fd + { "^([^:]+):(\\d+)$" regex not { "host:port expected" die } rep + net .dns .resolveIpv4 + -01 txt .consume .u16 + sockaddrIpv4 + +socket _ ==s + -01 +connect -- # TODO: error handling + } /connectFd deffd + + # 0 -> "host:port" + # 0 <- connected socket as file + { + connectFd sys .RDWR 0 sys .fdToFile + } /connect deffd +> /udp net .defv + +# vim: syn=elymas |
