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

@ -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 \