aboutsummaryrefslogtreecommitdiff
path: root/elymas/lib/net
diff options
context:
space:
mode:
authorDrahflow <drahflow@gmx.de>2013-09-02 11:27:01 +0200
committerDrahflow <drahflow@gmx.de>2013-09-02 11:27:01 +0200
commit92b6155a1c3a209936dddebb8bf3372ebee78f94 (patch)
tree8680757163dc8dbbea513b60f27945ec9c021af9 /elymas/lib/net
parentdd98844bd4968664f9dd7be996df596873733ecd (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.ey138
-rw-r--r--elymas/lib/net/tcp.ey37
-rw-r--r--elymas/lib/net/udp.ey36
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