4 ms·
Why is your lisp rendering ipv4 and ipv6 addresses as integers instead of octets...?
by titanomachy 2y ago
Why is your lisp rendering ipv4 and ipv6 addresses as integers instead of octets...?
- kazinator 2y agoBecause that's what they are; that's the representation. Look at the classic struct sockaddr_in structure it has a member sin_addr of type struct in_addr. What is that? In my header files here I have it as: typedef uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; }; The C structure has an integer, so the Lisp analog does also. C socket code does things like addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); INADDR_LOOPBACK is 127.0.0.1 encoded as an integer. It's easy to to do bitwise arithmetic on it. E.g. to apply a netmask like 255.0.0.0, you literally just form the netmask as 0xFF000000, and use your & operator: addr & 0xFF00000000. In the case of IPv6, there is a union: a view of the address as 16 bytes, 8 words, or 4 double words. Since I have bignum integers, I just made it a simple integer, so it looks like the IPv4 case. You can do bitwise arithmetic on it in a straightforward. We can get the addresses in text format like this: 1> (getaddrinfo "news.ycombinator.com") (#S(sockaddr-in canonname nil addr 3520653007 port 0 prefix 32) #S(sockaddr-in canonname nil addr 3520653007 port 0 prefix 32) #S(sockaddr-in6 canonname nil addr 50544109533264435600708011529282256934 port 0 flow-info 0 scope-id 0 prefix 128) #S(sockaddr-in6 canonname nil addr 50544109533264435600708011529282256934 port 0 flow-info 0 scope-id 0 prefix 128)) 2> (first *1) #S(sockaddr-in canonname nil addr 3520653007 port 0 prefix 32) 3> (third *1) #S(sockaddr-in6 canonname nil addr 50544109533264435600708011529282256934 port 0 flow-info 0 scope-id 0 prefix 128) 4> (str-inaddr *2.addr) "209.216.230.207" 5> (str-in6addr *3.addr) "2606:7100:1:67::26" str-inaddr and str-in6addr* take an integer and return a string. Their rough opposites return a structure, because the general text format can encode prefix and port number info. 6> (inaddr-str *4) #S(sockaddr-in canonname nil addr 3520653007 port 0 prefix 32) 7> (in6addr-str *5) #S(sockaddr-in6 canonname nil addr 50544109533264435600708011529282256934 port 0 flow-info 0 scope-id 0 prefix 128) The structures also support a generic method str-addr: 8> (mapcar .(str-addr) (getaddrinfo "news.ycombinator.com")) ("209.216.230.207" "209.216.230.207" "2606:7100:1:67::26" "2606:7100:1:67::26") This will take into account prefix and port number if they are present and nonzero. We could define a custom print method in the sockaddr base: 9> (defmeth sockaddr print (self stream pretty-p) (put-string `#<@(typeof self) @{self.(str-addr)}>` stream)) (meth sockaddr print) 10> (getaddrinfo "news.ycombinator.com") (#<sockaddr-in 209.216.230.207> #<sockaddr-in 209.216.230.207> #<sockaddr-in6 2606:7100:1:67::26> #<sockaddr-in6 2606:7100:1:67::26>)