Add tcp syn packet fingerprinting to redbean

This change also fixes bugs in enoprotoopt reporting with setsockopt and
getsockopt error returns.
This commit is contained in:
Justine Tunney 2022-07-17 02:40:39 -07:00
parent 866b21a151
commit 4d25f8c3c9
75 changed files with 1551 additions and 115 deletions

View file

@ -145,6 +145,7 @@ include tool/args/args.mk
include test/tool/args/test.mk
include third_party/linenoise/linenoise.mk
include third_party/maxmind/maxmind.mk
include net/finger/finger.mk
include third_party/double-conversion/double-conversion.mk
include third_party/lua/lua.mk
include third_party/make/make.mk
@ -202,6 +203,7 @@ include test/libc/release/test.mk
include test/libc/test.mk
include test/net/http/test.mk
include test/net/https/test.mk
include test/net/finger/test.mk
include test/net/test.mk
include test/tool/build/lib/test.mk
include test/tool/build/test.mk

View file

@ -44,6 +44,8 @@ kTcpOptnames:
.e TCP_SYNCNT,"SYNCNT" # int
.e TCP_NOTSENT_LOWAT,"NOTSENT_LOWAT" # int
.e TCP_WINDOW_CLAMP,"WINDOW_CLAMP" # int
.e TCP_SAVE_SYN,"SAVE_SYN" # int
.e TCP_SAVED_SYN,"SAVED_SYN" # buffer
.long MAGNUM_TERMINATOR
.endobj kTcpOptnames,globl,hidden
.overrun

View file

@ -32,6 +32,10 @@
* @param optname can be SO_{REUSE{PORT,ADDR},KEEPALIVE,etc.} etc.
* @return 0 on success, or -1 w/ errno
* @error ENOPROTOOPT for unknown (level,optname)
* @error EINVAL if `out_optlen` is invalid somehow
* @error ENOTSOCK if `fd` is valid but not a socket
* @error EBADF if `fd` isn't valid
* @error EFAULT if optval memory isn't valid
* @see libc/sysv/consts.sh for tuning catalogue
* @see setsockopt()
*/
@ -39,10 +43,8 @@ int getsockopt(int fd, int level, int optname, void *out_opt_optval,
uint32_t *out_optlen) {
int rc;
if (!level || !optname) {
rc = enoprotoopt(); /* our sysvconsts definition */
} else if (optname == -1) {
rc = 0; /* our sysvconsts definition */
if (level == -1 || !optname) {
rc = enoprotoopt(); /* see libc/sysv/consts.sh */
} else if (IsAsan() && (out_opt_optval && out_optlen &&
(!__asan_is_valid(out_optlen, sizeof(uint32_t)) ||
!__asan_is_valid(out_opt_optval, *out_optlen)))) {

View file

@ -49,6 +49,10 @@ static bool setsockopt_polyfill(int *optname) {
* @param optname can be SO_{REUSE{PORT,ADDR},KEEPALIVE,etc.} etc.
* @return 0 on success, or -1 w/ errno
* @error ENOPROTOOPT for unknown (level,optname)
* @error EINVAL if `optlen` is invalid somehow
* @error ENOTSOCK if `fd` is valid but not a socket
* @error EBADF if `fd` isn't valid
* @error EFAULT if optval memory isn't valid
* @see libc/sysv/consts.sh for tuning catalogue
* @see getsockopt()
*/
@ -56,8 +60,8 @@ int setsockopt(int fd, int level, int optname, const void *optval,
uint32_t optlen) {
int e, rc;
if (!optname) {
rc = enosys(); /* see libc/sysv/consts.sh */
if (level == -1 || !optname) {
rc = enoprotoopt(); /* see libc/sysv/consts.sh */
} else if ((!optval && optlen) ||
(IsAsan() && !__asan_is_valid(optval, optlen))) {
rc = efault();

View file

@ -649,9 +649,6 @@ syscon epoll EPOLLET 0x80000000 0x80000000 0x80000000 0x80000000 0x80000
# {set,get}sockopt(fd, level=SOL_SOCKET, X, ...)
#
# * 0 we define as EINVAL
# * -1 we define as no-op
#
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon so SO_DEBUG 1 1 1 1 1 1 # debugging is enabled; consensus
syscon so SO_TYPE 3 0x1008 0x1008 0x1008 0x1008 0x1008 # bsd consensus
@ -719,30 +716,30 @@ syscon sol SOL_IP 0 0 0 0 0 0 # consensus
syscon sol SOL_SOCKET 1 0xffff 0xffff 0xffff 0xffff 0xffff # yes it's actually 0xffff; bsd+nt consensus (todo: what's up with ipproto_icmp overlap)
syscon sol SOL_TCP 6 6 6 6 6 6 # consensus
syscon sol SOL_UDP 17 17 17 17 17 17 # consensus
syscon sol SOL_RAW 255 0 0 0 0 0
syscon sol SOL_RAW 255 -1 -1 -1 -1 -1
syscon sol SOL_IPV6 41 41 41 41 41 41
syscon sol SOL_ICMPV6 58 58 58 58 58 0
syscon sol SOL_AAL 265 0 0 0 0 0
syscon sol SOL_ALG 279 0 0 0 0 0
syscon sol SOL_ATM 264 0 0 0 0 0
syscon sol SOL_BLUETOOTH 274 0 0 0 0 0
syscon sol SOL_CAIF 278 0 0 0 0 0
syscon sol SOL_DCCP 269 0 0 0 0 0
syscon sol SOL_DECNET 261 0 0 0 0 0
syscon sol SOL_IRDA 266 0 0 0 0 0
syscon sol SOL_IUCV 277 0 0 0 0 0
syscon sol SOL_KCM 281 0 0 0 0 0
syscon sol SOL_LLC 268 0 0 0 0 0
syscon sol SOL_NETBEUI 267 0 0 0 0 0
syscon sol SOL_NETLINK 270 0 0 0 0 0
syscon sol SOL_NFC 280 0 0 0 0 0
syscon sol SOL_PACKET 263 0 0 0 0 0
syscon sol SOL_PNPIPE 275 0 0 0 0 0
syscon sol SOL_PPPOL2TP 273 0 0 0 0 0
syscon sol SOL_RDS 276 0 0 0 0 0
syscon sol SOL_RXRPC 272 0 0 0 0 0
syscon sol SOL_TIPC 271 0 0 0 0 0
syscon sol SOL_X25 262 0 0 0 0 0
syscon sol SOL_ICMPV6 58 58 58 58 58 -1
syscon sol SOL_AAL 265 -1 -1 -1 -1 -1
syscon sol SOL_ALG 279 -1 -1 -1 -1 -1
syscon sol SOL_ATM 264 -1 -1 -1 -1 -1
syscon sol SOL_BLUETOOTH 274 -1 -1 -1 -1 -1
syscon sol SOL_CAIF 278 -1 -1 -1 -1 -1
syscon sol SOL_DCCP 269 -1 -1 -1 -1 -1
syscon sol SOL_DECNET 261 -1 -1 -1 -1 -1
syscon sol SOL_IRDA 266 -1 -1 -1 -1 -1
syscon sol SOL_IUCV 277 -1 -1 -1 -1 -1
syscon sol SOL_KCM 281 -1 -1 -1 -1 -1
syscon sol SOL_LLC 268 -1 -1 -1 -1 -1
syscon sol SOL_NETBEUI 267 -1 -1 -1 -1 -1
syscon sol SOL_NETLINK 270 -1 -1 -1 -1 -1
syscon sol SOL_NFC 280 -1 -1 -1 -1 -1
syscon sol SOL_PACKET 263 -1 -1 -1 -1 -1
syscon sol SOL_PNPIPE 275 -1 -1 -1 -1 -1
syscon sol SOL_PPPOL2TP 273 -1 -1 -1 -1 -1
syscon sol SOL_RDS 276 -1 -1 -1 -1 -1
syscon sol SOL_RXRPC 272 -1 -1 -1 -1 -1
syscon sol SOL_TIPC 271 -1 -1 -1 -1 -1
syscon sol SOL_X25 262 -1 -1 -1 -1 -1
syscon alg ALG_SET_KEY 1 0 0 0 0 0
syscon alg ALG_SET_IV 2 0 0 0 0 0
@ -751,12 +748,9 @@ syscon alg ALG_SET_AEAD_ASSOCLEN 4 0 0 0 0 0
syscon alg ALG_SET_AEAD_AUTHSIZE 5 0 0 0 0 0
syscon alg ALG_SET_DRBG_ENTROPY 6 0 0 0 0 0
# {set,get}sockopt(fd, level=IPPROTO_TCP, X, ...)
# {set,get}sockopt(fd, level=SOL_TCP, X, ...)
# » most elite of all tuning groups
#
# * 0 we define as EINVAL
# * -1 we define as no-op
#
# @see https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
# @see https://www.iana.org/assignments/tcp-parameters/tcp-parameters.txt
#
@ -923,33 +917,33 @@ syscon iproto IPPROTO_ICMP 1 1 1 1 1 1 # consensus
syscon iproto IPPROTO_TCP 6 6 6 6 6 6 # consensus
syscon iproto IPPROTO_UDP 17 17 17 17 17 17 # consensus
syscon iproto IPPROTO_RAW 255 255 255 255 255 255 # consensus
syscon iproto IPPROTO_HOPOPTS 0 0 0 0 0 0 # consensus
syscon iproto IPPROTO_HOPOPTS -1 -1 -1 -1 -1 -1 # consensus
syscon iproto IPPROTO_IDP 22 22 22 22 22 22 # consensus
syscon iproto IPPROTO_IGMP 2 2 2 2 2 2 # consensus
syscon iproto IPPROTO_PUP 12 12 12 12 12 12 # consensus
syscon iproto IPPROTO_AH 51 51 51 51 51 0 # unix consensus
syscon iproto IPPROTO_DSTOPTS 60 60 60 60 60 0 # unix consensus
syscon iproto IPPROTO_EGP 8 8 8 8 8 0 # unix consensus
syscon iproto IPPROTO_ENCAP 98 98 98 98 98 0 # unix consensus
syscon iproto IPPROTO_ESP 50 50 50 50 50 0 # unix consensus
syscon iproto IPPROTO_FRAGMENT 44 44 44 44 44 0 # unix consensus
syscon iproto IPPROTO_GRE 47 47 47 47 47 0 # unix consensus
syscon iproto IPPROTO_ICMPV6 58 58 58 58 58 0 # unix consensus
syscon iproto IPPROTO_IPIP 4 4 4 4 4 0 # unix consensus
syscon iproto IPPROTO_IPV6 41 41 41 41 41 0 # unix consensus
syscon iproto IPPROTO_NONE 59 59 59 59 59 0 # unix consensus
syscon iproto IPPROTO_PIM 103 103 103 103 103 0 # unix consensus
syscon iproto IPPROTO_ROUTING 43 43 43 43 43 0 # unix consensus
syscon iproto IPPROTO_RSVP 46 46 46 46 46 0 # unix consensus
syscon iproto IPPROTO_TP 29 29 29 29 29 0 # unix consensus
syscon iproto IPPROTO_MPLS 137 0 137 137 137 0
syscon iproto IPPROTO_MTP 92 92 92 0 0 0
syscon iproto IPPROTO_SCTP 132 132 132 0 0 0
syscon iproto IPPROTO_MH 135 0 135 0 0 0
syscon iproto IPPROTO_UDPLITE 136 0 136 0 0 0
syscon iproto IPPROTO_BEETPH 94 0 0 0 0 0
syscon iproto IPPROTO_COMP 108 0 0 0 0 0
syscon iproto IPPROTO_DCCP 33 0 0 0 0 0
syscon iproto IPPROTO_AH 51 51 51 51 51 -1 # unix consensus
syscon iproto IPPROTO_DSTOPTS 60 60 60 60 60 -1 # unix consensus
syscon iproto IPPROTO_EGP 8 8 8 8 8 -1 # unix consensus
syscon iproto IPPROTO_ENCAP 98 98 98 98 98 -1 # unix consensus
syscon iproto IPPROTO_ESP 50 50 50 50 50 -1 # unix consensus
syscon iproto IPPROTO_FRAGMENT 44 44 44 44 44 -1 # unix consensus
syscon iproto IPPROTO_GRE 47 47 47 47 47 -1 # unix consensus
syscon iproto IPPROTO_ICMPV6 58 58 58 58 58 -1 # unix consensus
syscon iproto IPPROTO_IPIP 4 4 4 4 4 -1 # unix consensus
syscon iproto IPPROTO_IPV6 41 41 41 41 41 -1 # unix consensus
syscon iproto IPPROTO_NONE 59 59 59 59 59 -1 # unix consensus
syscon iproto IPPROTO_PIM 103 103 103 103 103 -1 # unix consensus
syscon iproto IPPROTO_ROUTING 43 43 43 43 43 -1 # unix consensus
syscon iproto IPPROTO_RSVP 46 46 46 46 46 -1 # unix consensus
syscon iproto IPPROTO_TP 29 29 29 29 29 -1 # unix consensus
syscon iproto IPPROTO_MPLS 137 -1 137 137 137 -1
syscon iproto IPPROTO_MTP 92 92 92 -1 -1 -1
syscon iproto IPPROTO_SCTP 132 132 132 -1 -1 -1
syscon iproto IPPROTO_MH 135 -1 135 -1 -1 -1
syscon iproto IPPROTO_UDPLITE 136 -1 136 -1 -1 -1
syscon iproto IPPROTO_BEETPH 94 -1 -1 -1 -1 -1
syscon iproto IPPROTO_COMP 108 -1 -1 -1 -1 -1
syscon iproto IPPROTO_DCCP 33 -1 -1 -1 -1 -1
syscon sio SIOCADDMULTI 0x8931 0x80206931 0x80206931 0x80206931 0x80206931 0 # bsd consensus
syscon sio SIOCATMARK 0x8905 0x40047307 0x40047307 0x40047307 0x40047307 0 # bsd consensus

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_AH,51,51,51,51,51,0
.syscon iproto,IPPROTO_AH,51,51,51,51,51,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_BEETPH,94,0,0,0,0,0
.syscon iproto,IPPROTO_BEETPH,94,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_COMP,108,0,0,0,0,0
.syscon iproto,IPPROTO_COMP,108,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_DCCP,33,0,0,0,0,0
.syscon iproto,IPPROTO_DCCP,33,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_DSTOPTS,60,60,60,60,60,0
.syscon iproto,IPPROTO_DSTOPTS,60,60,60,60,60,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_EGP,8,8,8,8,8,0
.syscon iproto,IPPROTO_EGP,8,8,8,8,8,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_ENCAP,98,98,98,98,98,0
.syscon iproto,IPPROTO_ENCAP,98,98,98,98,98,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_ESP,50,50,50,50,50,0
.syscon iproto,IPPROTO_ESP,50,50,50,50,50,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_FRAGMENT,44,44,44,44,44,0
.syscon iproto,IPPROTO_FRAGMENT,44,44,44,44,44,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_GRE,47,47,47,47,47,0
.syscon iproto,IPPROTO_GRE,47,47,47,47,47,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_HOPOPTS,0,0,0,0,0,0
.syscon iproto,IPPROTO_HOPOPTS,-1,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_ICMPV6,58,58,58,58,58,0
.syscon iproto,IPPROTO_ICMPV6,58,58,58,58,58,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_IPIP,4,4,4,4,4,0
.syscon iproto,IPPROTO_IPIP,4,4,4,4,4,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_IPV6,41,41,41,41,41,0
.syscon iproto,IPPROTO_IPV6,41,41,41,41,41,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_MH,135,0,135,0,0,0
.syscon iproto,IPPROTO_MH,135,-1,135,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_MPLS,137,0,137,137,137,0
.syscon iproto,IPPROTO_MPLS,137,-1,137,137,137,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_MTP,92,92,92,0,0,0
.syscon iproto,IPPROTO_MTP,92,92,92,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_NONE,59,59,59,59,59,0
.syscon iproto,IPPROTO_NONE,59,59,59,59,59,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_PIM,103,103,103,103,103,0
.syscon iproto,IPPROTO_PIM,103,103,103,103,103,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_ROUTING,43,43,43,43,43,0
.syscon iproto,IPPROTO_ROUTING,43,43,43,43,43,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_RSVP,46,46,46,46,46,0
.syscon iproto,IPPROTO_RSVP,46,46,46,46,46,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_SCTP,132,132,132,0,0,0
.syscon iproto,IPPROTO_SCTP,132,132,132,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_TP,29,29,29,29,29,0
.syscon iproto,IPPROTO_TP,29,29,29,29,29,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon iproto,IPPROTO_UDPLITE,136,0,136,0,0,0
.syscon iproto,IPPROTO_UDPLITE,136,-1,136,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_AAL,265,0,0,0,0,0
.syscon sol,SOL_AAL,265,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_ALG,279,0,0,0,0,0
.syscon sol,SOL_ALG,279,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_ATM,264,0,0,0,0,0
.syscon sol,SOL_ATM,264,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_BLUETOOTH,274,0,0,0,0,0
.syscon sol,SOL_BLUETOOTH,274,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_CAIF,278,0,0,0,0,0
.syscon sol,SOL_CAIF,278,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_DCCP,269,0,0,0,0,0
.syscon sol,SOL_DCCP,269,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_DECNET,261,0,0,0,0,0
.syscon sol,SOL_DECNET,261,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_ICMPV6,58,58,58,58,58,0
.syscon sol,SOL_ICMPV6,58,58,58,58,58,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_IRDA,266,0,0,0,0,0
.syscon sol,SOL_IRDA,266,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_IUCV,277,0,0,0,0,0
.syscon sol,SOL_IUCV,277,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_KCM,281,0,0,0,0,0
.syscon sol,SOL_KCM,281,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_LLC,268,0,0,0,0,0
.syscon sol,SOL_LLC,268,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_NETBEUI,267,0,0,0,0,0
.syscon sol,SOL_NETBEUI,267,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_NETLINK,270,0,0,0,0,0
.syscon sol,SOL_NETLINK,270,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_NFC,280,0,0,0,0,0
.syscon sol,SOL_NFC,280,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_PACKET,263,0,0,0,0,0
.syscon sol,SOL_PACKET,263,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_PNPIPE,275,0,0,0,0,0
.syscon sol,SOL_PNPIPE,275,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_PPPOL2TP,273,0,0,0,0,0
.syscon sol,SOL_PPPOL2TP,273,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_RAW,255,0,0,0,0,0
.syscon sol,SOL_RAW,255,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_RDS,276,0,0,0,0,0
.syscon sol,SOL_RDS,276,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_RXRPC,272,0,0,0,0,0
.syscon sol,SOL_RXRPC,272,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_TIPC,271,0,0,0,0,0
.syscon sol,SOL_TIPC,271,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sol,SOL_X25,262,0,0,0,0,0
.syscon sol,SOL_X25,262,-1,-1,-1,-1,-1

133
net/finger/describesyn.c Normal file
View file

@ -0,0 +1,133 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/fmt/itoa.h"
#include "net/finger/finger.h"
/**
* Describes IP+TCP SYN packet
*
* The layout looks as follows:
*
* TTL:OPTIONS:WSIZE:MSS
*
* The `TTL`, `WSIZE`, and `MSS` fields are unsigned decimal fields.
*
* The `OPTIONS` field communicates the ordering of the commonly used
* subset of tcp options. The following character mappings are defined.
* TCP options not on this list will be ignored.
*
* - E: End of Option list
* - N: No-Operation
* - M: Maxmimum Segment Size
* - K: Window Scale
* - O: SACK Permitted
* - A: SACK
* - e: Echo (obsolete)
* - r: Echo reply (obsolete)
* - T: Timestamps
*
* @param q receives nul-terminated string
* @param m is byte capacity of `q`
* @param p is syn packet
* @param n is byte length of `p`
* @return pointer past last written byte in `q` or null if not a syn packet
* @see https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xhtml
*/
char *DescribeSyn(char *q, size_t m, const char *p, size_t n) {
char *e;
int i, j, k, r, iplen, tcplen, ttl, wsize, mss;
if (n >= 20 + 20 && n >= (iplen = (p[0] & 0x0F) * 4) + 20 &&
n >= iplen + (tcplen = ((p[iplen + 12] & 0xF0) >> 4) * 4)) {
e = q + m;
n = iplen + tcplen;
// Time to Live
// ttl<=256 Crisco, Solaris 6
// ttl<=128 Windows, OpenVMS 8+
// ttl<= 64 Mac, Linux, BSD, Solaris 8+, Tru64, HP-UX
ttl = p[8] & 255;
wsize = READ16BE(p + 14);
if (q + 13 <= e) {
q = FormatUint32(q, ttl);
*q++ = ':';
}
// TCP Options
// We care about the order and presence of leading common options.
for (mss = j = 0, i = iplen + 20; i < n; ++j) {
k = p[i] & 255;
if (k < 9 && q + 1 < e) {
*q++ = "ENMKOAerT"[k];
}
if (k == 2 && i + 4 <= n) {
mss = READ16BE(p + 2);
}
if (k == 1 || // no-operation
k == 2 || // maximum segment size
k == 3 || // window scale
k == 4 || // sack permitted
k == 8) { // timestamps
if (k == 1) {
// no-operation option has no length byte
//
// ┌───┐
// │ 1 │
// └───┘
//
++i;
} else if (i + 1 < n) {
// a normal tcp option should have
//
// ┌──┬───┬───┐
// │OP│LEN│...│
// └──┴───┴───┘
//
// e.g. sack permitted is encoded as
//
// ┌───┬───┐
// │ 4 │ 2 │
// └───┴───┘
//
// e.g. window scale of `7` would be encoded as
//
// ┌───┬───┬───┐
// │ 3 │ 3 │ 7 │
// └───┴───┴───┘
//
i += p[i + 1] & 255;
} else {
break;
}
} else {
break;
}
}
if (q + (1 + 12) * 2 <= e) {
*q++ = ':';
q = FormatUint32(q, wsize);
*q++ = ':';
q = FormatUint32(q, mss);
}
if (q < e) {
*q = 0;
}
return q;
} else {
return 0;
}
}

13
net/finger/finger.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef COSMOPOLITAN_NET_FINGER_FINGER_H_
#define COSMOPOLITAN_NET_FINGER_FINGER_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
char *DescribeSyn(char *, size_t, const char *, size_t);
const char *GetOsName(int);
int GetSynFingerOs(uint32_t);
uint32_t FingerSyn(const char *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_NET_FINGER_FINGER_H_ */

47
net/finger/finger.mk Normal file
View file

@ -0,0 +1,47 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += NET_FINGER
NET_FINGER_ARTIFACTS += NET_FINGER_A
NET_FINGER = $(NET_FINGER_A_DEPS) $(NET_FINGER_A)
NET_FINGER_A = o/$(MODE)/net/finger/finger.a
NET_FINGER_A_FILES := $(wildcard net/finger/*)
NET_FINGER_A_HDRS = $(filter %.h,$(NET_FINGER_A_FILES))
NET_FINGER_A_INCS := $(filter %.inc,$(NET_FINGER_A_FILES))
NET_FINGER_A_SRCS_C = $(filter %.c,$(NET_FINGER_A_FILES))
NET_FINGER_A_SRCS_S = $(filter %.S,$(NET_FINGER_A_FILES))
NET_FINGER_A_SRCS = $(NET_FINGER_A_SRCS_S) $(NET_FINGER_A_SRCS_C)
NET_FINGER_A_OBJS_C = $(NET_FINGER_A_SRCS_C:%.c=o/$(MODE)/%.o)
NET_FINGER_A_OBJS_S = $(NET_FINGER_A_SRCS_S:%.S=o/$(MODE)/%.o)
NET_FINGER_A_OBJS = $(NET_FINGER_A_OBJS_S) $(NET_FINGER_A_OBJS_C)
NET_FINGER_A_CHECKS = \
$(NET_FINGER_A).pkg \
$(NET_FINGER_A_HDRS:%=o/$(MODE)/%.ok)
NET_FINGER_A_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_NEXGEN32E
NET_FINGER_A_DEPS := \
$(call uniq,$(foreach x,$(NET_FINGER_A_DIRECTDEPS),$($(x))))
$(NET_FINGER_A): \
net/finger/ \
$(NET_FINGER_A).pkg \
$(NET_FINGER_A_OBJS)
$(NET_FINGER_A).pkg: \
$(NET_FINGER_A_OBJS) \
$(foreach x,$(NET_FINGER_A_DIRECTDEPS),$($(x)_A).pkg)
NET_FINGER_LIBS = $(foreach x,$(NET_FINGER_ARTIFACTS),$($(x)))
NET_FINGER_SRCS = $(foreach x,$(NET_FINGER_ARTIFACTS),$($(x)_SRCS))
NET_FINGER_HDRS = $(foreach x,$(NET_FINGER_ARTIFACTS),$($(x)_HDRS))
NET_FINGER_OBJS = $(foreach x,$(NET_FINGER_ARTIFACTS),$($(x)_OBJS))
NET_FINGER_CHECKS = $(foreach x,$(NET_FINGER_ARTIFACTS),$($(x)_CHECKS))
.PHONY: o/$(MODE)/net/finger
o/$(MODE)/net/finger: \
$(NET_FINGER_CHECKS)

64
net/finger/fingersyn.c Normal file
View file

@ -0,0 +1,64 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h"
/**
* Fingers IP+TCP SYN packet.
*
* This returns a hash-like magic number that reflects the SYN packet
* structure, e.g. ordering of options, maximum segment size, etc.
*/
uint32_t FingerSyn(const char *p, size_t n) {
uint32_t h = 0;
int i, j, k, q, r, iplen, tcplen, ttl;
if (n >= 20 + 20 && n >= (iplen = (p[0] & 0x0F) * 4) + 20 &&
n >= iplen + (tcplen = ((p[iplen + 12] & 0xF0) >> 4) * 4)) {
n = iplen + tcplen;
// Time to Live
// ttl<=256 Crisco, Solaris 6
// ttl<=128 Windows, OpenVMS 8+
// ttl<=64 Mac, Linux, BSD, Solaris 8+, Tru64, HP-UX
ttl = p[8] & 255;
h += bsr(MAX(1, ttl - 1));
h *= 0x9e3779b1;
// TCP Options
// We care about the order and presence of leading common options.
for (j = 0, i = iplen + 20; i < n; ++j) {
k = p[i] & 255;
if (k == 0 || k == 1 || k == 2 || k == 3 || k == 4 || k == 8) {
if (k <= 1) {
++i;
} else if (i + 1 < n) {
i += p[i + 1] & 255;
} else {
break;
}
} else {
break;
}
h += j << 8 | k;
h *= 0x9e3779b1;
}
if (!h) {
++h;
}
}
return h;
}

45
net/finger/getosname.c Normal file
View file

@ -0,0 +1,45 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/nexgen32e/bsr.h"
#include "net/finger/finger.h"
const char *GetOsName(int os) {
if (os) {
switch (bsr(os)) {
case 0:
return "LINUX";
case 1:
return "METAL";
case 2:
return "WINDOWS";
case 3:
return "XNU";
case 4:
return "OPENBSD";
case 5:
return "FREEBSD";
case 6:
return "NETBSD";
default:
return 0;
}
} else {
return 0;
}
}

View file

@ -0,0 +1,40 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "net/finger/finger.h"
/**
* Turns result of FingerprintSyn() into operating system.
*/
int GetSynFingerOs(uint32_t x) {
switch (x) {
case 0x7e7a6599:
return XNU;
case 0xbb724187:
return LINUX;
case 0xb228b212:
return WINDOWS;
case 0x77c30887:
return FREEBSD;
case 0xc45d694b:
return OPENBSD;
default:
return 0;
}
}

View file

@ -2,5 +2,6 @@
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
.PHONY: o/$(MODE)/net
o/$(MODE)/net: o/$(MODE)/net/http \
o/$(MODE)/net: o/$(MODE)/net/finger \
o/$(MODE)/net/http \
o/$(MODE)/net/https

View file

@ -48,6 +48,10 @@ STATIC_YOINK("libc/testlib/hyperion.txt");
#define THREADS 8
__attribute__((__constructor__)) static void init(void) {
if (IsOpenbsd()) exit(0); // TODO(jart): flakes :'(
}
void PullSomeZipFilesIntoLinkage(void) {
gmtime(0);
}

View file

@ -0,0 +1,290 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/log/check.h"
#include "libc/rand/rand.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
#include "net/finger/finger.h"
#define DESCRIBESYN(s) MyDescribeSyn(s, sizeof(s) - 1)
char o[128];
char *MyDescribeSyn(const char *p, size_t n) {
char *q;
rngset(o, sizeof(o), lemur64, -1);
q = DescribeSyn(o, sizeof(o), p, n);
CHECK_NOTNULL(q);
CHECK_EQ(strlen(o), q - o);
return o;
}
TEST(DescribeSyn, badPacket) {
ASSERT_EQ(NULL, DescribeSyn(o, sizeof(o), "123", 3));
}
TEST(DescribeSyn, testWindows7) {
// version = 4
// ihl = 20
// dscp = 0
// ecn = 0
// lengthtotal = 52
// identification = 5538
// flags = 2
// fragmentoffset = 0
// ttl = 128
// protocol = 6
// ipchecksum = 48124
// srcip = 127.10.10.150
// dstip = 127.10.10.124
//
// srcport = 50078
// dstport = 7000
// sequence = 305725139
// acknumber = 0
// dataoffset = 8
// ns = 0
// cwr = 0
// ece = 0
// urg = 0
// ack = 0
// psh = 0
// rst = 0
// syn = 1
// fin = 0
// wsize = 8192
// tcpchecksum = 13806
// urgpointer = 0
//
// option 2 4 5 180 (Maximum Segment Size)
// option 1 (No-Operation)
// option 3 3 2 (Window Scale)
// option 1 (No-Operation)
// option 1 (No-Operation)
// option 4 2 (SACK Permitted)
static char s[] = "\
\x45\x00\x00\x34\x15\xa2\x40\x00\x80\x06\xbb\xfc\x7f\x0a\x0a\x96\
\x7f\x0a\x0a\x7c\xc3\x9e\x1b\x58\x12\x38\xfe\xd3\x00\x00\x00\x00\
\x80\x02\x20\x00\x35\xee\x00\x00\x02\x04\x05\xb4\x01\x03\x03\x02\
\x01\x01\x04\x02";
EXPECT_STREQ("128:MNKNNO:2710:52", DESCRIBESYN(s));
}
TEST(DescribeSyn, testWindows10) {
// version = 4
// ihl = 20
// dscp = 0
// ecn = 0
// lengthtotal = 52
// identification = 24981
// flags = 2
// fragmentoffset = 0
// ttl = 128
// protocol = 6
// ipchecksum = 28818
// srcip = 127.10.10.13
// dstip = 127.10.10.124
//
// srcport = 60914
// dstport = 7000
// sequence = 3953567664
// acknumber = 0
// dataoffset = 8
// ns = 0
// cwr = 0
// ece = 0
// urg = 0
// ack = 0
// psh = 0
// rst = 0
// syn = 1
// fin = 0
// wsize = 64240
// tcpchecksum = 44768
// urgpointer = 0
//
// option 2 4 5 180 (Maximum Segment Size)
// option 1 (No-Operation)
// option 3 3 8 (Window Scale)
// option 1 (No-Operation)
// option 1 (No-Operation)
// option 4 2 (SACK Permitted)
static char s[] = "\
\x45\x00\x00\x34\x61\x95\x40\x00\x80\x06\x70\x92\x7f\x0a\x0a\x0d\
\x7f\x0a\x0a\x7c\xed\xf2\x1b\x58\xeb\xa6\xa7\xb0\x00\x00\x00\x00\
\x80\x02\xfa\xf0\xae\xe0\x00\x00\x02\x04\x05\xb4\x01\x03\x03\x08\
\x01\x01\x04\x02";
EXPECT_STREQ("128:MNKNNO:2573:52", DESCRIBESYN(s));
}
TEST(FingerprintSyn, testLinuxAlpine_isLinux) {
// version = 4
// ihl = 20
// dscp = 0
// ecn = 0
// lengthtotal = 60
// identification = 16488
// flags = 2
// fragmentoffset = 0
// ttl = 64
// protocol = 6
// ipchecksum = 53576
// srcip = 127.10.10.124
// dstip = 127.10.10.124
//
// srcport = 60978
// dstport = 7000
// sequence = 4272530606
// acknumber = 0
// dataoffset = 10
// ns = 0
// cwr = 0
// ece = 0
// urg = 0
// ack = 0
// psh = 0
// rst = 0
// syn = 1
// fin = 0
// wsize = 65495
// tcpchecksum = 10554
// urgpointer = 0
//
// option 2 4 255 215 (Maximum Segment Size)
// option 4 2 (SACK Permitted)
// option 8 10 67 61 171 124 0 0 0 0 (Timestamps)
// option 1 (No-Operation)
// option 3 3 7 (Window Scale)
static char s[] = "\
\x45\x00\x00\x3c\x40\x68\x40\x00\x40\x06\xd1\x48\x7f\x0a\x0a\x7c\
\x7f\x0a\x0a\x7c\xee\x32\x1b\x58\xfe\xa9\xa4\xae\x00\x00\x00\x00\
\xa0\x02\xff\xd7\x29\x3a\x00\x00\x02\x04\xff\xd7\x04\x02\x08\x0a\
\x43\x3d\xab\x7c\x00\x00\x00\x00\x01\x03\x03\x07";
EXPECT_STREQ("64:MOTNK:2684:60", DESCRIBESYN(s));
}
TEST(FingerprintSyn, testLinuxDebian_isLinux) {
// version = 4
// ihl = 20
// dscp = 0
// ecn = 0
// lengthtotal = 60
// identification = 51388
// flags = 2
// fragmentoffset = 0
// ttl = 64
// protocol = 6
// ipchecksum = 18678
// srcip = 127.10.10.122
// dstip = 127.10.10.124
//
// srcport = 57892
// dstport = 7000
// sequence = 4142527109
// acknumber = 0
// dataoffset = 10
// ns = 0
// cwr = 0
// ece = 0
// urg = 0
// ack = 0
// psh = 0
// rst = 0
// syn = 1
// fin = 0
// wsize = 64240
// tcpchecksum = 24492
// urgpointer = 0
//
// option 2 4 5 180 (Maximum Segment Size)
// option 4 2 (SACK Permitted)
// option 8 10 74 67 147 41 0 0 0 0 (Timestamps)
// option 1 (No-Operation)
// option 3 3 7 (Window Scale)
static char s[] = "\
\x45\x00\x00\x3c\xc8\xbc\x40\x00\x40\x06\x48\xf6\x7f\x0a\x0a\x7a\
\x7f\x0a\x0a\x7c\xe2\x24\x1b\x58\xf6\xe9\xf2\x85\x00\x00\x00\x00\
\xa0\x02\xfa\xf0\x5f\xac\x00\x00\x02\x04\x05\xb4\x04\x02\x08\x0a\
\x4a\x43\x93\x29\x00\x00\x00\x00\x01\x03\x03\x07";
EXPECT_STREQ("64:MOTNK:2682:60", DESCRIBESYN(s));
}
TEST(FingerprintSyn, testLinuxFastOpen_isLinux) {
static char s[] = "\
\x45\x00\x00\x99\x6f\x97\x40\x00\x40\x06\xa1\xbc\x7f\x0a\x0a\x7c\
\x7f\x0a\x0a\x7c\xee\x3a\x1b\x58\xe1\xbd\xd2\x8d\x00\x00\x00\x00\
\xd0\x02\xff\xd7\x29\x97\x00\x00\x02\x04\xff\xd7\x04\x02\x08\x0a\
\x43\x3f\x21\xf8\x00\x00\x00\x00\x01\x03\x03\x07\x22\x0a\xd4\x75\
\x4f\x06\xc0\x97\x25\x6c\x01\x01";
EXPECT_STREQ("64:MOTNK:2684:153", DESCRIBESYN(s));
}
TEST(FingerprintSyn, testLinuxGceVm_isLinux) {
static char s[] = "\
\x45\x20\x00\x3c\x59\x9a\x40\x00\x3b\x06\xb0\xe4\x23\xe2\xfc\xb5\
\x7f\x0a\x0a\x7c\xd2\xfe\x1b\x58\xf5\xb2\xf6\xca\x00\x00\x00\x00\
\xa0\x02\xff\x28\x16\xe7\x00\x00\x02\x04\x05\x8c\x04\x02\x08\x0a\
\xb6\x4d\x6b\xd8\x00\x00\x00\x00\x01\x03\x03\x07";
EXPECT_STREQ("59:MOTNK:64693:60", DESCRIBESYN(s));
}
TEST(FingerprintSyn, testOpenbsd) {
static char s[] = "\
\x45\x00\x00\x40\x7c\x71\x40\x00\x40\x06\x95\x32\x7f\x0a\x0a\x85\
\x7f\x0a\x0a\x7c\xa2\x91\x1b\x58\x53\x54\xbc\xc5\x00\x00\x00\x00\
\xb0\x02\x40\x00\x70\xf7\x00\x00\x02\x04\x05\xb4\x01\x01\x04\x02\
\x01\x03\x03\x06\x01\x01\x08\x0a\xa2\x70\xeb\x7a\x00\x00\x00\x00";
EXPECT_STREQ("64:MNNONKNNT:2693:64", DESCRIBESYN(s));
}
TEST(FingerprintSyn, testXnu) {
static char s[] = "\
\x45\x00\x00\x40\x00\x00\x40\x00\x40\x06\x11\xb1\x7f\x0a\x0a\x78\
\x7f\x0a\x0a\x7c\xd3\x63\x1b\x58\xe6\xd5\xf8\x7e\x00\x00\x00\x00\
\xb0\x02\xff\xff\x70\x36\x00\x00\x02\x04\x05\xb4\x01\x03\x03\x06\
\x01\x01\x08\x0a\x25\x85\xaa\x28\x00\x00\x00\x00\x04\x02\x00\x00";
EXPECT_STREQ("64:MNKNNTOE:2680:64", DESCRIBESYN(s));
}
TEST(FingerprintSyn, testFreebsd12) {
static char s[] = "\
\x45\x00\x00\x3c\x00\x00\x40\x00\x40\x06\x11\xae\x7f\x0a\x0a\x7f\
\x7f\x0a\x0a\x7c\xde\x81\x1b\x58\x23\x39\xfc\x6b\x00\x00\x00\x00\
\xa0\x02\xff\xff\x8c\x8c\x00\x00\x02\x04\x05\xb4\x01\x03\x03\x06\
\x04\x02\x08\x0a\x1f\xa1\x59\x46\x00\x00\x00\x00";
EXPECT_STREQ("64:MNKOT:2687:60", DESCRIBESYN(s));
}
TEST(FingerprintSyn, testRedbeanGceVm_isFreebsd) {
static char s[] = "\
\x45\x20\x00\x3c\x00\x00\x40\x00\x3b\x06\x92\xe4\x23\xee\x74\x44\
\x7f\x0a\x0a\x7c\x5a\x6e\x1b\x58\x0a\x15\xba\x1a\x00\x00\x00\x00\
\xa0\x02\xff\xff\xe4\x60\x00\x00\x02\x04\x05\x8c\x01\x03\x03\x06\
\x04\x02\x08\x0a\xc9\x06\xb4\x13\x00\x00\x00\x00";
EXPECT_STREQ("59:MNKOT:29764:60", DESCRIBESYN(s));
}
TEST(FingerprintSyn, testNetbsd_isFreebsdSadly) {
static char s[] = "\
\x45\x00\x00\x3c\x00\x00\x40\x00\x40\x06\x11\x98\x7f\x0a\x0a\x95\
\x7f\x0a\x0a\x7c\xfc\x18\x1b\x58\x8e\xb8\x1b\xfe\x00\x00\x00\x00\
\xa0\x02\x80\x00\xdc\xb6\x00\x00\x02\x04\x05\xb4\x01\x03\x03\x03\
\x04\x02\x08\x0a\x00\x00\x00\x01\x00\x00\x00\x00";
EXPECT_STREQ("64:MNKOT:2709:60", DESCRIBESYN(s));
}

View file

@ -0,0 +1,122 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/testlib.h"
#include "net/finger/finger.h"
TEST(FingerSyn, testWindows7_isWindows) {
static char s[] = "\
\x45\x00\x00\x34\x15\xa2\x40\x00\x80\x06\xbb\xfc\x7f\x0a\x0a\x96\
\x7f\x0a\x0a\x7c\xc3\x9e\x1b\x58\x12\x38\xfe\xd3\x00\x00\x00\x00\
\x80\x02\x20\x00\x35\xee\x00\x00\x02\x04\x05\xb4\x01\x03\x03\x02\
\x01\x01\x04\x02";
EXPECT_EQ(WINDOWS, GetSynFingerOs(FingerSyn(s, sizeof(s) - 1)));
}
TEST(FingerSyn, testWindows10_isWindows) {
static char s[] = "\
\x45\x00\x00\x34\x61\x95\x40\x00\x80\x06\x70\x92\x7f\x0a\x0a\x0d\
\x7f\x0a\x0a\x7c\xed\xf2\x1b\x58\xeb\xa6\xa7\xb0\x00\x00\x00\x00\
\x80\x02\xfa\xf0\xae\xe0\x00\x00\x02\x04\x05\xb4\x01\x03\x03\x08\
\x01\x01\x04\x02";
EXPECT_EQ(WINDOWS, GetSynFingerOs(FingerSyn(s, sizeof(s) - 1)));
}
TEST(FingerSyn, testLinuxAlpine_isLinux) {
static char s[] = "\
\x45\x00\x00\x3c\x40\x68\x40\x00\x40\x06\xd1\x48\x7f\x0a\x0a\x7c\
\x7f\x0a\x0a\x7c\xee\x32\x1b\x58\xfe\xa9\xa4\xae\x00\x00\x00\x00\
\xa0\x02\xff\xd7\x29\x3a\x00\x00\x02\x04\xff\xd7\x04\x02\x08\x0a\
\x43\x3d\xab\x7c\x00\x00\x00\x00\x01\x03\x03\x07";
EXPECT_EQ(LINUX, GetSynFingerOs(FingerSyn(s, sizeof(s) - 1)));
}
TEST(FingerSyn, testLinuxDebian_isLinux) {
static char s[] = "\
\x45\x00\x00\x3c\xc8\xbc\x40\x00\x40\x06\x48\xf6\x7f\x0a\x0a\x7a\
\x7f\x0a\x0a\x7c\xe2\x24\x1b\x58\xf6\xe9\xf2\x85\x00\x00\x00\x00\
\xa0\x02\xfa\xf0\x5f\xac\x00\x00\x02\x04\x05\xb4\x04\x02\x08\x0a\
\x4a\x43\x93\x29\x00\x00\x00\x00\x01\x03\x03\x07";
EXPECT_EQ(LINUX, GetSynFingerOs(FingerSyn(s, sizeof(s) - 1)));
}
TEST(FingerSyn, testLinuxFastOpen_isLinux) {
static char s[] = "\
\x45\x00\x00\x99\x6f\x97\x40\x00\x40\x06\xa1\xbc\x7f\x00\x00\x7c\
\x7f\x00\x00\x7c\xee\x3a\x1b\x58\xe1\xbd\xd2\x8d\x00\x00\x00\x00\
\xd0\x02\xff\xd7\x29\x97\x00\x00\x02\x04\xff\xd7\x04\x02\x08\x0a\
\x43\x3f\x21\xf8\x00\x00\x00\x00\x01\x03\x03\x07\x22\x0a\xd4\x75\
\x4f\x06\xc0\x97\x25\x6c\x01\x01";
EXPECT_EQ(LINUX, GetSynFingerOs(FingerSyn(s, sizeof(s) - 1)));
}
TEST(FingerSyn, testLinuxGceVm_isLinux) {
static char s[] = "\
\x45\x20\x00\x3c\x59\x9a\x40\x00\x3b\x06\xb0\xe4\x23\xe2\xfc\xb5\
\x7f\x00\x00\x7c\xd2\xfe\x1b\x58\xf5\xb2\xf6\xca\x00\x00\x00\x00\
\xa0\x02\xff\x28\x16\xe7\x00\x00\x02\x04\x05\x8c\x04\x02\x08\x0a\
\xb6\x4d\x6b\xd8\x00\x00\x00\x00\x01\x03\x03\x07";
EXPECT_EQ(LINUX, GetSynFingerOs(FingerSyn(s, sizeof(s) - 1)));
}
TEST(FingerSyn, testOpenbsd) {
static char s[] = "\
\x45\x00\x00\x40\x7c\x71\x40\x00\x40\x06\x95\x32\x7f\x00\x00\x85\
\x7f\x00\x00\x7c\xa2\x91\x1b\x58\x53\x54\xbc\xc5\x00\x00\x00\x00\
\xb0\x02\x40\x00\x70\xf7\x00\x00\x02\x04\x05\xb4\x01\x01\x04\x02\
\x01\x03\x03\x06\x01\x01\x08\x0a\xa2\x70\xeb\x7a\x00\x00\x00\x00";
EXPECT_EQ(OPENBSD, GetSynFingerOs(FingerSyn(s, sizeof(s) - 1)));
}
TEST(FingerSyn, testXnu) {
static char s[] = "\
\x45\x00\x00\x40\x00\x00\x40\x00\x40\x06\x11\xb1\x7f\x00\x00\x78\
\x7f\x00\x00\x7c\xd3\x63\x1b\x58\xe6\xd5\xf8\x7e\x00\x00\x00\x00\
\xb0\x02\xff\xff\x70\x36\x00\x00\x02\x04\x05\xb4\x01\x03\x03\x06\
\x01\x01\x08\x0a\x25\x85\xaa\x28\x00\x00\x00\x00\x04\x02\x00\x00";
EXPECT_EQ(XNU, GetSynFingerOs(FingerSyn(s, sizeof(s) - 1)));
}
TEST(FingerSyn, testFreebsd12) {
static char s[] = "\
\x45\x00\x00\x3c\x00\x00\x40\x00\x40\x06\x11\xae\x7f\x00\x00\x7f\
\x7f\x00\x00\x7c\xde\x81\x1b\x58\x23\x39\xfc\x6b\x00\x00\x00\x00\
\xa0\x02\xff\xff\x8c\x8c\x00\x00\x02\x04\x05\xb4\x01\x03\x03\x06\
\x04\x02\x08\x0a\x1f\xa1\x59\x46\x00\x00\x00\x00";
EXPECT_EQ(FREEBSD, GetSynFingerOs(FingerSyn(s, sizeof(s) - 1)));
}
TEST(FingerSyn, testRedbeanGceVm_isFreebsd) {
static char s[] = "\
\x45\x20\x00\x3c\x00\x00\x40\x00\x3b\x06\x92\xe4\x23\xee\x74\x44\
\x7f\x00\x00\x7c\x5a\x6e\x1b\x58\x0a\x15\xba\x1a\x00\x00\x00\x00\
\xa0\x02\xff\xff\xe4\x60\x00\x00\x02\x04\x05\x8c\x01\x03\x03\x06\
\x04\x02\x08\x0a\xc9\x06\xb4\x13\x00\x00\x00\x00";
EXPECT_EQ(FREEBSD, GetSynFingerOs(FingerSyn(s, sizeof(s) - 1)));
}
TEST(FingerSyn, testNetbsd_isFreebsdSadly) {
static char s[] = "\
\x45\x00\x00\x3c\x00\x00\x40\x00\x40\x06\x11\x98\x7f\x00\x00\x95\
\x7f\x00\x00\x7c\xfc\x18\x1b\x58\x8e\xb8\x1b\xfe\x00\x00\x00\x00\
\xa0\x02\x80\x00\xdc\xb6\x00\x00\x02\x04\x05\xb4\x01\x03\x03\x03\
\x04\x02\x08\x0a\x00\x00\x00\x01\x00\x00\x00\x00";
EXPECT_EQ(FREEBSD, GetSynFingerOs(FingerSyn(s, sizeof(s) - 1)));
}

46
test/net/finger/test.mk Normal file
View file

@ -0,0 +1,46 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += TEST_NET_FINGER
TEST_NET_FINGER_SRCS := $(wildcard test/net/finger/*.c)
TEST_NET_FINGER_SRCS_TEST = $(filter %_test.c,$(TEST_NET_FINGER_SRCS))
TEST_NET_FINGER_BINS = $(TEST_NET_FINGER_COMS) $(TEST_NET_FINGER_COMS:%=%.dbg)
TEST_NET_FINGER_OBJS = \
$(TEST_NET_FINGER_SRCS:%.c=o/$(MODE)/%.o)
TEST_NET_FINGER_COMS = \
$(TEST_NET_FINGER_SRCS:%.c=o/$(MODE)/%.com)
TEST_NET_FINGER_TESTS = \
$(TEST_NET_FINGER_SRCS_TEST:%.c=o/$(MODE)/%.com.ok)
TEST_NET_FINGER_CHECKS = \
$(TEST_NET_FINGER_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
TEST_NET_FINGER_DIRECTDEPS = \
NET_FINGER \
LIBC_LOG \
LIBC_TESTLIB \
THIRD_PARTY_MBEDTLS
TEST_NET_FINGER_DEPS := \
$(call uniq,$(foreach x,$(TEST_NET_FINGER_DIRECTDEPS),$($(x))))
o/$(MODE)/test/net/finger/finger.pkg: \
$(TEST_NET_FINGER_OBJS) \
$(foreach x,$(TEST_NET_FINGER_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/test/net/finger/%.com.dbg: \
$(TEST_NET_FINGER_DEPS) \
o/$(MODE)/test/net/finger/%.o \
$(LIBC_TESTMAIN) \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
.PHONY: o/$(MODE)/test/net/finger
o/$(MODE)/test/net/finger: \
$(TEST_NET_FINGER_BINS) \
$(TEST_NET_FINGER_CHECKS)

View file

@ -2,5 +2,6 @@
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
.PHONY: o/$(MODE)/test/net
o/$(MODE)/test/net: o/$(MODE)/test/net/http \
o/$(MODE)/test/net: o/$(MODE)/test/net/finger \
o/$(MODE)/test/net/http \
o/$(MODE)/test/net/https

View file

@ -1085,6 +1085,7 @@ static bool IsSockoptBool(int l, int x) {
return x == TCP_NODELAY || //
x == TCP_CORK || //
x == TCP_QUICKACK || //
x == TCP_SAVE_SYN || //
x == TCP_FASTOPEN_CONNECT || //
x == TCP_DEFER_ACCEPT; //
} else if (l = SOL_IP) {
@ -1136,6 +1137,11 @@ static int LuaUnixSetsockopt(lua_State *L) {
fd = luaL_checkinteger(L, 1);
level = luaL_checkinteger(L, 2);
optname = luaL_checkinteger(L, 3);
if (level == -1 || optname == 0) {
NoProtocolOption:
enoprotoopt();
return SysretErrno(L, "setsockopt", olderr);
}
if (IsSockoptBool(level, optname)) {
// unix.setsockopt(fd:int, level:int, optname:int, value:bool)
// ├─→ true
@ -1167,14 +1173,14 @@ static int LuaUnixSetsockopt(lua_State *L) {
optval = &l;
optsize = sizeof(l);
} else {
einval();
return SysretErrno(L, "setsockopt", olderr);
goto NoProtocolOption;
}
return SysretBool(L, "setsockopt", olderr,
setsockopt(fd, level, optname, optval, optsize));
}
static int LuaUnixGetsockopt(lua_State *L) {
char *p;
uint32_t size;
struct linger l;
struct timeval tv;
@ -1182,6 +1188,11 @@ static int LuaUnixGetsockopt(lua_State *L) {
fd = luaL_checkinteger(L, 1);
level = luaL_checkinteger(L, 2);
optname = luaL_checkinteger(L, 3);
if (level == -1 || optname == 0) {
NoProtocolOption:
enoprotoopt();
return SysretErrno(L, "setsockopt", olderr);
}
if (IsSockoptBool(level, optname) || IsSockoptInt(level, optname)) {
// unix.getsockopt(fd:int, level:int, optname:int)
// ├─→ value:int
@ -1214,8 +1225,20 @@ static int LuaUnixGetsockopt(lua_State *L) {
lua_pushboolean(L, !!l.l_onoff);
return 1;
}
} else if (level == SOL_TCP && optname == TCP_SAVED_SYN) {
// unix.getsockopt(fd:int, unix.SOL_TCP, unix.SO_SAVED_SYN)
// ├─→ syn_packet_bytes:str
// └─→ nil, unix.Errno
if ((p = malloc((size = 1500)))) {
if (getsockopt(fd, level, optname, p, &size) != -1) {
lua_pushlstring(L, p, size);
free(p);
return 1;
}
free(p);
}
} else {
einval();
goto NoProtocolOption;
}
return SysretErrno(L, "getsockopt", olderr);
}

View file

@ -20,8 +20,20 @@ db:exec[[
INSERT INTO test (content) VALUES ('Hello Sqlite3');
]]
function OnServerListen(fd, ip, port)
unix.setsockopt(fd, unix.SOL_TCP, unix.TCP_SAVE_SYN, true)
return false
end
function OnClientConnection(ip, port, serverip, serverport)
syn, synerr = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_SAVED_SYN)
end
-- this intercepts all requests if it's defined
function OnHttpRequest()
Log(kLogInfo, "client is running %s and reports %s" % {
finger.GetSynFingerOs(finger.FingerSyn(syn)),
GetHeader('User-Agent')})
if HasParam('magic') then
Write('<p>\r\n')
Write('OnHttpRequest() has intercepted your request<br>\r\n')

65
tool/net/demo/finger.lua Normal file
View file

@ -0,0 +1,65 @@
-- fingerprinting example
Write[[<!doctype html>
<title>redbean binary trees</title>
<style>
body { padding: 1em; }
h1 a { color: inherit; text-decoration: none; }
h1 img { border: none; vertical-align: middle; }
input { margin: 1em; padding: .5em; }
p { word-break: break-word; max-width: 650px; }
dt { font-family: monospace; }
dd { margin-top: 1em; margin-bottom: 1em; }
.hdr { text-indent: -1em; padding-left: 1em; }
</style>
<h1>
<a href="/"><img src="/redbean.png"></a>
<a href="finger.lua">redbean finger demo</a>
</h1>
]]
Write[[
<h2>Your TCP SYN Packet</h2>
]]
-- See .init.lua hooks which set SYN and SYNERR globals.
if syn then
if syn ~= '' then
Write('<dl>\r\n')
Write('<dt>syn = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_SAVED_SYN)\r\n')
Write('<dd>')
Write(EscapeHtml(EncodeLua(syn)))
Write('\r\n')
Write('<dt>finger.FingerSyn(syn)\r\n')
Write('<dd>')
Write(EscapeHtml(EncodeLua(finger.FingerSyn(syn))))
Write('\r\n')
Write('<dt>finger.DescribeSyn(syn)\r\n')
Write('<dd>')
Write(EscapeHtml(EncodeLua(finger.DescribeSyn(syn))))
Write('\r\n')
Write('<dt>finger.GetSynFingerOs(finger.FingerSyn(syn))\r\n')
Write('<dd>')
Write(EscapeHtml(EncodeLua(finger.GetSynFingerOs(finger.FingerSyn(syn)))))
Write('\r\n')
Write('</dl>\r\n')
else
Write([[
<p>
your operating system returned an empty string as the syn
packet! did you remember to use setsockopt(TCP_SAVE_SYN)?
did you call getsockopt(TCP_SAVED_SYN) more than once?
</p>
]])
end
else
Write([[
<p>
your operating system most likely doesn't support TCP_SAVED_SYN
because getsockopt() returned %s.
</p>
]] % {EscapeHtml(tostring(synerr))})
end

View file

@ -1974,6 +1974,100 @@ MAXMIND MODULE
For further details, please see maxmind.lua in redbean-demo.com.
────────────────────────────────────────────────────────────────────────────────
FINGER MODULE
This is an experimental module that, like the maxmind module, gives
you insight into what kind of device is connecting to your redbean.
This module can help you protect your redbean because it provides
tools for identifying clients that misrepresent themselves. For
example the User-Agent header might report itself as a Windows
computer when the SYN packet says it's a Linux computer.
function OnServerListen(fd, ip, port)
unix.setsockopt(fd, unix.SOL_TCP, unix.TCP_SAVE_SYN, true)
return false
end
function OnClientConnection(ip, port, serverip, serverport)
fd = GetClientFd()
syn = unix.getsockopt(fd, unix.SOL_TCP, unix.TCP_SAVED_SYN)
end
function OnHttpRequest()
Log(kLogInfo, "client is running %s and reports %s" % {
finger.GetSynFingerOs(finger.FingerSyn(syn)),
GetHeader('User-Agent')})
Route()
end
The following functions are provided.
finger.FingerSyn(syn_packet_bytes:str)
├─→ synfinger:uint32
└─→ nil, error:str
Fingerprints IP+TCP SYN packet.
This returns a hash-like magic number that reflects the SYN packet
structure, e.g. ordering of options, maximum segment size, etc. We
make no guarantees this hashing algorithm won't change as we learn
more about the optimal way to fingerprint, so be sure to save your
syn packets too if you're using this feature, in case they need to
be rehashed in the future.
This function is nil/error propagating.
finger.GetSynFingerOs(synfinger:uint32)
├─→ osname:str
└─→ nil, error:str
Fingerprints IP+TCP SYN packet.
If `synfinger` is a known hard-coded magic number, then one of the
following strings may be returned:
- `"LINUX"`
- `"WINDOWS"`
- `"XNU"`
- `"NETBSD"`
- `"FREEBSD"`
- `"OPENBSD"`
If this function returns nil, then one thing you can do to help is
file an issue and share with us your SYN packet specimens. The way
we prefer to receive them is in EncodeLua(syn_packet_bytes) format
along with details on the operating system which you must know.
finger.DescribeSyn(syn_packet_bytes:str)
├─→ description:str
└─→ nil, error:str
Describes IP+TCP SYN packet.
The layout looks as follows:
TTL:OPTIONS:WSIZE:MSS
The `TTL`, `WSIZE`, and `MSS` fields are unsigned decimal fields.
The `OPTIONS` field communicates the ordering of the commonly used
subset of tcp options. The following character mappings are defined.
TCP options not on this list will be ignored.
- E: End of Option list
- N: No-Operation
- M: Maxmimum Segment Size
- K: Window Scale
- O: SACK Permitted
- A: SACK
- e: Echo (obsolete)
- r: Echo reply (obsolete)
- T: Timestamps
This function is nil/error propagating.
────────────────────────────────────────────────────────────────────────────────
ARGON2 MODULE
@ -3071,6 +3165,17 @@ UNIX MODULE
`level` and `optname` may be one of the following pairs. The ellipses
type signature above changes depending on which options are used.
`optname` is the option feature magic number. The constants for
these will be set to `0` if the option isn't supported on the host
platform.
Raises `ENOPROTOOPT` if your `level` / `optname` combination isn't
valid, recognized, or supported on the host platform.
Raises `ENOTSOCK` if `fd` is valid but isn't a socket.
Raises `EBADF` if `fd` isn't valid.
unix.getsockopt(fd:int, level:int, optname:int)
├─→ value:int
└─→ nil, unix.Errno
@ -3145,9 +3250,19 @@ UNIX MODULE
close(). Sometimes it's desirable to have extra assurance on errors
happened, even if it comes at the cost of performance.
Returns `EINVAL` if settings other than the above are used.
unix.setsockopt(serverfd:int, unix.SOL_TCP, unix.TCP_SAVE_SYN, enabled:int)
├─→ true
└─→ nil, unix.Errno
unix.getsockopt(clientfd:int, unix.SOL_TCP, unix.TCP_SAVED_SYN)
├─→ syn_packet_bytes:str
└─→ nil, unix.Errno
Returns `ENOSYS` if setting isn't supported by the host OS.
This `TCP_SAVED_SYN` option may be used to retrieve the bytes of the
TCP SYN packet that the client sent when the connection for `fd` was
opened. In order for this to work, `TCP_SAVE_SYN` must have been set
earlier on the listening socket. This is Linux-only. You can use the
`OnServerListen` hook to enable SYN saving in your Redbean. When the
`TCP_SAVE_SYN` option isn't used, this may return empty string.
unix.poll({[fd:int]=events:int, ...}[, timeoutms:int])
├─→ {[fd:int]=revents:int, ...}

98
tool/net/lfinger.c Normal file
View file

@ -0,0 +1,98 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "net/finger/finger.h"
#include "third_party/lua/lauxlib.h"
// finger.DescribeSyn(syn_packet_bytes:str)
// ├─→ description:str
// └─→ nil, error:str
static int LuaDescribeSyn(lua_State *L) {
char *q, *r;
size_t n, m;
const char *p;
luaL_Buffer b;
if (!lua_isnoneornil(L, 1)) {
p = luaL_checklstring(L, 1, &n);
m = 128;
q = luaL_buffinitsize(L, &b, m);
if ((r = DescribeSyn(q, m, p, n))) {
luaL_pushresultsize(&b, r - q);
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, "bad syn packet");
return 2;
}
} else {
return lua_gettop(L);
}
}
// finger.FingerSyn(syn_packet_bytes:str)
// ├─→ synfinger:uint32
// └─→ nil, error:str
static int LuaFingerSyn(lua_State *L) {
size_t n;
uint32_t x;
const char *p;
if (!lua_isnoneornil(L, 1)) {
p = luaL_checklstring(L, 1, &n);
if ((x = FingerSyn(p, n))) {
lua_pushinteger(L, x);
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, "bad syn packet");
return 2;
}
} else {
return lua_gettop(L);
}
}
// finger.GetSynFingerOs(synfinger:uint32)
// ├─→ osname:str
// └─→ nil, error:str
static int LuaGetSynFingerOs(lua_State *L) {
int os;
if (!lua_isnoneornil(L, 1)) {
if ((os = GetSynFingerOs(luaL_checkinteger(L, 1)))) {
lua_pushstring(L, GetOsName(os));
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, "unknown syn os fingerprint");
return 2;
}
} else {
return lua_gettop(L);
}
}
static const luaL_Reg kLuaFinger[] = {
{"DescribeSyn", LuaDescribeSyn}, //
{"FingerSyn", LuaFingerSyn}, //
{"GetSynFingerOs", LuaGetSynFingerOs}, //
{0}, //
};
int LuaFinger(lua_State *L) {
luaL_newlib(L, kLuaFinger);
return 1;
}

11
tool/net/lfinger.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef COSMOPOLITAN_TOOL_NET_LFINGER_H_
#define COSMOPOLITAN_TOOL_NET_LFINGER_H_
#include "third_party/lua/lauxlib.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int LuaFinger(lua_State *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_NET_LFINGER_H_ */

View file

@ -54,6 +54,7 @@ TOOL_NET_DIRECTDEPS = \
LIBC_UNICODE \
LIBC_X \
LIBC_ZIPOS \
NET_FINGER \
NET_HTTP \
NET_HTTPS \
THIRD_PARTY_ARGON2 \
@ -95,6 +96,7 @@ o/$(MODE)/tool/net/redbean.com.dbg: \
$(TOOL_NET_DEPS) \
o/$(MODE)/tool/net/redbean.o \
o/$(MODE)/tool/net/lfuncs.o \
o/$(MODE)/tool/net/lfinger.o \
o/$(MODE)/tool/net/lre.o \
o/$(MODE)/tool/net/ljson.o \
o/$(MODE)/tool/net/lmaxmind.o \
@ -178,6 +180,7 @@ o/$(MODE)/tool/net/demo/unix-dir.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-finger.lua.zip.o \
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
o/$(MODE)/tool/net/demo/finger.lua.zip.o \
o/$(MODE)/tool/net/demo/call-lua-module.lua.zip.o \
o/$(MODE)/tool/net/demo/store-asset.lua.zip.o \
o/$(MODE)/tool/net/demo/maxmind.lua.zip.o \
@ -214,6 +217,7 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \
$(TOOL_NET_DEPS) \
o/$(MODE)/tool/net/redbean.o \
o/$(MODE)/tool/net/lfuncs.o \
o/$(MODE)/tool/net/lfinger.o \
o/$(MODE)/tool/net/lre.o \
o/$(MODE)/tool/net/ljson.o \
o/$(MODE)/tool/net/lmaxmind.o \
@ -229,6 +233,7 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \
o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-finger.lua.zip.o \
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
o/$(MODE)/tool/net/demo/finger.lua.zip.o \
o/$(MODE)/tool/net/demo/store-asset.lua.zip.o \
o/$(MODE)/tool/net/demo/call-lua-module.lua.zip.o \
o/$(MODE)/tool/net/demo/redbean.lua.zip.o \
@ -331,6 +336,7 @@ o/$(MODE)/tool/net/redbean-unsecure.com.dbg: \
$(TOOL_NET_DEPS) \
o/$(MODE)/tool/net/redbean-unsecure.o \
o/$(MODE)/tool/net/lfuncs.o \
o/$(MODE)/tool/net/lfinger.o \
o/$(MODE)/tool/net/lre.o \
o/$(MODE)/tool/net/ljson.o \
o/$(MODE)/tool/net/lmaxmind.o \

View file

@ -112,6 +112,7 @@
#include "third_party/zlib/zlib.h"
#include "tool/args/args.h"
#include "tool/build/lib/case.h"
#include "tool/net/lfinger.h"
#include "tool/net/lfuncs.h"
#include "tool/net/ljson.h"
#include "tool/net/luacheck.h"
@ -5253,6 +5254,7 @@ static const luaL_Reg kLuaLibs[] = {
{"argon2", luaopen_argon2}, //
{"lsqlite3", luaopen_lsqlite3}, //
{"maxmind", LuaMaxmind}, //
{"finger", LuaFinger}, //
{"re", LuaRe}, //
{"unix", LuaUnix}, //
};

137
tool/viz/maxmind.c Normal file
View file

@ -0,0 +1,137 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.internal.h"
#include "libc/stdio/stdio.h"
#include "net/http/http.h"
#include "net/http/ip.h"
#include "third_party/maxmind/maxminddb.h"
#define PATH(...) \
(const char *const[]) { \
__VA_ARGS__, 0 \
}
MMDB_s *ipdb, *asdb;
int PrintIpInfo(const char *ipstr) {
int error;
bool uhoh;
int64_t ip;
uint16_t cc;
MMDB_entry_data_s e, f;
MMDB_lookup_result_s r;
if ((ip = ParseIp(ipstr, -1)) == -1) {
fprintf(stderr, "BAD IP: %s\n", ipstr);
return -1;
}
r = MMDB_lookup(ipdb, ip, &error);
CHECK_EQ(MMDB_SUCCESS, error);
if (!r.found_entry) {
fprintf(stderr, "NOT FOUND: %s\n", ipstr);
return -1;
}
printf("%hhu.%hhu.%hhu.%hhu\n", ip >> 24, ip >> 16, ip >> 8, ip);
if (!MMDB_aget_value(&r.entry, &e, PATH("location", "metro_code"))) {
printf("%s: %s\n", "metro", GetMetroName(e.uint16));
}
if (!MMDB_aget_value(&r.entry, &e, PATH("postal", "code"))) {
printf("%s: %.*s\n", "postal", e.data_size, e.utf8_string);
}
if (!MMDB_aget_value(&r.entry, &e, PATH("city", "names", "en"))) {
printf("%s: %.*s\n", "city", e.data_size, e.utf8_string);
}
if (!MMDB_aget_value(&r.entry, &e, PATH("subdivisions", "0", "iso_code")) &&
!MMDB_aget_value(&r.entry, &f,
PATH("subdivisions", "0", "names", "en"))) {
printf("%s: %.*s (%.*s)\n", "region", e.data_size, e.utf8_string,
f.data_size, f.utf8_string);
}
if (!MMDB_aget_value(&r.entry, &e, PATH("country", "iso_code")) &&
!MMDB_aget_value(&r.entry, &f, PATH("country", "names", "en"))) {
printf("%s: %.*s (%.*s)\n", "country", e.data_size, e.utf8_string,
f.data_size, f.utf8_string);
cc = READ16LE(e.utf8_string);
} else {
cc = 0;
}
if (!MMDB_aget_value(&r.entry, &e, PATH("registered_country", "iso_code")) &&
!MMDB_aget_value(&r.entry, &f,
PATH("registered_country", "names", "en"))) {
uhoh = cc && cc != READ16LE(e.utf8_string);
printf("%s%s: %.*s (%.*s)%s\n", uhoh ? "\e[1m" : "", "registered",
e.data_size, e.utf8_string, f.data_size, f.utf8_string,
uhoh ? "\e[0m" : "");
}
if ((!MMDB_aget_value(&r.entry, &e,
PATH("country", "is_in_european_union")) &&
e.boolean) ||
(!MMDB_aget_value(&r.entry, &e,
PATH("registered_country", "is_in_european_union")) &&
e.boolean)) {
printf("%s: %s\n", "is_in_european_union", "true");
}
if (!MMDB_aget_value(&r.entry, &e, PATH("continent", "code")) &&
!MMDB_aget_value(&r.entry, &f, PATH("continent", "names", "en"))) {
printf("%s: %.*s (%.*s)\n", "continent", e.data_size, e.utf8_string,
f.data_size, f.utf8_string);
}
if (!MMDB_aget_value(&r.entry, &e, PATH("location", "time_zone"))) {
printf("%s: %.*s\n", "timezone", e.data_size, e.utf8_string);
}
if (!MMDB_aget_value(&r.entry, &e, PATH("location", "latitude")) &&
!MMDB_aget_value(&r.entry, &f, PATH("location", "longitude"))) {
printf("%s: %g %g\n", "location", e.double_value, f.double_value);
}
if (!MMDB_aget_value(&r.entry, &e, PATH("location", "accuracy_radius"))) {
printf("%s: %dkm\n", "accuracy", e.uint16);
}
printf("%s: %s\n", "category", GetIpCategoryName(CategorizeIp(ip)));
if ((r = MMDB_lookup(asdb, ip, &error)).found_entry &&
!MMDB_aget_value(&r.entry, &e, PATH("autonomous_system_number")) &&
!MMDB_aget_value(&r.entry, &f, PATH("autonomous_system_organization"))) {
printf("%s: AS%u (%.*s)\n", "asn", e.uint32, f.data_size, f.utf8_string);
}
return 0;
}
int main(int argc, char *argv[]) {
int i, rc;
ipdb = gc(calloc(1, sizeof(MMDB_s)));
CHECK_EQ(MMDB_SUCCESS,
MMDB_open("/usr/local/share/maxmind/GeoLite2-City.mmdb", 0, ipdb));
asdb = gc(calloc(1, sizeof(MMDB_s)));
CHECK_EQ(MMDB_SUCCESS,
MMDB_open("/usr/local/share/maxmind/GeoLite2-ASN.mmdb", 0, asdb));
for (rc = 0, i = 1; i < argc; ++i) {
if (PrintIpInfo(argv[i]) != -1) {
if (i + 1 < argc) printf("\n");
} else {
fprintf(stderr, "NOT FOUND: %s\n", argv[i]);
rc = 1;
}
}
MMDB_close(asdb);
MMDB_close(ipdb);
return rc;
}

156
tool/viz/tcp.c Normal file
View file

@ -0,0 +1,156 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/bits/bits.h"
#include "libc/stdio/stdio.h"
// clang-format off
static char ip[] = "\
\x45\x00\x00\x3c\xc8\xbc\x40\x00\x40\x06\x48\xf6\x7f\x0a\x0a\x7a\
\x7f\x0a\x0a\x7c\xe2\x24\x1b\x58\xf6\xe9\xf2\x85\x00\x00\x00\x00\
\xa0\x02\xfa\xf0\x5f\xac\x00\x00\x02\x04\x05\xb4\x04\x02\x08\x0a\
\x4a\x43\x93\x29\x00\x00\x00\x00\x01\x03\x03\x07";
static const char *const kTcpOptionNames[] = {
[0] = "End of Option List",
[1] = "No-Operation",
[2] = "Maximum Segment Size",
[3] = "Window Scale",
[4] = "SACK Permitted",
[5] = "SACK",
[6] = "Echo (obsoleted by option 8)",
[7] = "Echo Reply (obsoleted by option 8)",
[8] = "Timestamps",
[9] = "Partial Order Connection Permitted (obsolete)",
[10] = "Partial Order Service Profile (obsolete)",
[11] = "CC (obsolete)",
[12] = "CC.NEW (obsolete)",
[13] = "CC.ECHO (obsolete)",
[14] = "TCP Alternate Checksum Request (obsolete)",
[15] = "TCP Alternate Checksum Data (obsolete)",
[16] = "Skeeter",
[17] = "Bubba",
[18] = "Trailer Checksum Option",
[19] = "MD5 Signature Option (obsoleted by option 29)",
[20] = "SCPS Capabilities",
[21] = "Selective Negative Acknowledgements",
[22] = "Record Boundaries",
[23] = "Corruption experienced",
[24] = "SNAP",
[25] = "Unassigned (released 2000-12-18)",
[26] = "TCP Compression Filter",
[27] = "Quick-Start Response",
[28] = "User Timeout Option",
[29] = "TCP Authentication Option (TCP-AO)",
[30] = "Multipath TCP (MPTCP)",
[31] = "Reserved (known unauthorized use without proper IANA assignm",
[32] = "Reserved (known unauthorized use without proper IANA assignm",
[33] = "Reserved (known unauthorized use without proper IANA assignm",
[34] = "variable TCP Fast Open Cookie",
[35] = "Reserved",
[69] = "Encryption Negotiation",
[253] = "RFC3692-1",
[254] = "RFC3692-2",
};
int main(int argc, char *argv[]) {
int version = (ip[0] & 0b11110000) >> 4;
int ihl = (ip[0] & 0b00001111) >> 0;
int dscp = (ip[1] & 0b11111100) >> 2;
int ecn = (ip[1] & 0b00000011) >> 0;
int lengthtotal = READ16BE(ip + 2);
int identification = READ16BE(ip + 4);
int flags = (ip[6] & 0b11100000) >> 5;
int fragmentoffset = (ip[6] & 0b00011111) << 8 | (ip[7] & 255);
int ttl = ip[8] & 255;
int protocol = ip[9] & 255;
int ipchecksum = (ip[10] & 255) << 8 | (ip[11] & 255);
int srcip = READ32BE(ip + 12);
int dstip = READ32BE(ip + 16);
printf("\n");
printf("// version = %u\n", version);
printf("// ihl = %u\n", ihl * 4);
printf("// dscp = %u\n", dscp);
printf("// ecn = %u\n", ecn);
printf("// lengthtotal = %u\n", lengthtotal);
printf("// identification = %u\n", identification);
printf("// flags = %u\n", flags);
printf("// fragmentoffset = %u\n", fragmentoffset);
printf("// ttl = %u\n", ttl);
printf("// protocol = %u\n", protocol);
printf("// ipchecksum = %u\n", ipchecksum);
printf("// srcip = %hhu.%hhu.%hhu.%hhu\n", srcip >> 24, srcip >> 16, srcip >> 8, srcip);
printf("// dstip = %hhu.%hhu.%hhu.%hhu\n", dstip >> 24, dstip >> 16, dstip >> 8, dstip);
printf("// \n");
char *tcp = ip + ihl * 4;
int srcport = READ16BE(tcp + 0);
int dstport = READ16BE(tcp + 2);
int sequence = READ32BE(tcp + 4);
int acknumber = READ32BE(tcp + 8);
int dataoffset = (tcp[12] & 0b11110000) >> 4;
bool ns = !!(tcp[12] & 0b00000001);
bool cwr = !!(tcp[13] & 0b10000000);
bool ece = !!(tcp[13] & 0b01000000);
bool urg = !!(tcp[13] & 0b00100000);
bool ack = !!(tcp[13] & 0b00010000);
bool psh = !!(tcp[13] & 0b00001000);
bool rst = !!(tcp[13] & 0b00000100);
bool syn = !!(tcp[13] & 0b00000010);
bool fin = !!(tcp[13] & 0b00000001);
int wsize = READ16BE(tcp + 14);
int tcpchecksum = READ16BE(tcp + 16);
int urgpointer = READ16BE(tcp + 18);
printf("// srcport = %u\n", srcport);
printf("// dstport = %u\n", dstport);
printf("// sequence = %u\n", sequence);
printf("// acknumber = %u\n", acknumber);
printf("// dataoffset = %u\n", dataoffset);
printf("// ns = %u\n", ns);
printf("// cwr = %u\n", cwr);
printf("// ece = %u\n", ece);
printf("// urg = %u\n", urg);
printf("// ack = %u\n", ack);
printf("// psh = %u\n", psh);
printf("// rst = %u\n", rst);
printf("// syn = %u\n", syn);
printf("// fin = %u\n", fin);
printf("// wsize = %u\n", wsize);
printf("// tcpchecksum = %u\n", tcpchecksum);
printf("// urgpointer = %u\n", urgpointer);
printf("// \n");
int c, i, j, n;
for (i = 20; i + 1 < dataoffset * 4;) {
printf("// option");
switch ((c = tcp[i] & 255)) {
case 0:
case 1:
printf(" %u", c);
++i;
break;
default:
n = tcp[i + 1] & 255;
printf(" %u %u", c, n);
for (j = 2; j < n; ++j) {
printf(" %u", tcp[i + j] & 255);
}
i += n;
break;
}
if (kTcpOptionNames[c]) {
printf(" (%s)", kTcpOptionNames[c]);
}
printf("\n");
}
return 0;
}

View file

@ -50,8 +50,9 @@ TOOL_VIZ_DIRECTDEPS = \
THIRD_PARTY_DLMALLOC \
THIRD_PARTY_GDTOA \
THIRD_PARTY_GETOPT \
THIRD_PARTY_STB \
THIRD_PARTY_MAXMIND \
THIRD_PARTY_MUSL \
THIRD_PARTY_STB \
THIRD_PARTY_XED \
THIRD_PARTY_ZLIB \
TOOL_DECODE_LIB \