#ifndef WKS_H
#define WKS_H
#if BYTE_ORDER == LITTLE_ENDIAN
# define TCP (0x0000000000706374llu)
# define UDP (0x0000000000706475llu)
#elif BYTE_ORDER == BIG_ENDIAN
# define TCP (0x7463700000000000llu)
# define UDP (0x7564700000000000llu)
#else
# error "byte order unknown"
#endif
static really_inline int32_t scan_protocol(
const char *name, size_t length, uint8_t *protocol)
{
static const int8_t zero_masks[48] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
uint64_t key;
uint64_t mask;
const int8_t *zero_mask = &zero_masks[32 - (length & 0x1f)];
memcpy(&mask, zero_mask, 8);
memcpy(&key, name, sizeof(key));
key |= (key & 0x4040404040404040) >> 1;
key &= mask;
if (key == TCP)
return (void)(*protocol = 6), 1;
else if (key == UDP)
return (void)(*protocol = 17), 1;
else
return scan_int8(name, length, protocol);
}
typedef struct service service_t;
struct service {
struct {
const char name[16];
size_t length;
} key;
uint16_t port;
};
#define UNKNOWN_SERVICE() { { "", 0 }, 0 }
#define SERVICE(name, port) { { name, sizeof(name) - 1 }, port }
static const service_t services[64] = {
UNKNOWN_SERVICE(),
SERVICE("snmptrap", 162),
SERVICE("pop3s", 995),
SERVICE("pop3", 110),
SERVICE("ldaps", 636),
SERVICE("domain", 53),
SERVICE("nntps", 563),
SERVICE("nntp", 119),
UNKNOWN_SERVICE(),
UNKNOWN_SERVICE(),
UNKNOWN_SERVICE(),
UNKNOWN_SERVICE(),
SERVICE("ftps-data", 989),
UNKNOWN_SERVICE(),
UNKNOWN_SERVICE(),
SERVICE("imaps", 993),
SERVICE("imap", 143),
SERVICE("time", 37),
UNKNOWN_SERVICE(),
UNKNOWN_SERVICE(),
SERVICE("kerberos", 88),
UNKNOWN_SERVICE(),
UNKNOWN_SERVICE(),
SERVICE("ftp", 21),
SERVICE("ntp", 123),
SERVICE("whoispp", 63),
SERVICE("ssh", 22),
UNKNOWN_SERVICE(),
SERVICE("nicname", 43),
UNKNOWN_SERVICE(),
UNKNOWN_SERVICE(),
UNKNOWN_SERVICE(),
SERVICE("ptp-general", 320),
UNKNOWN_SERVICE(),
UNKNOWN_SERVICE(),
SERVICE("domain-s", 853),
SERVICE("ftp-data", 20),
SERVICE("ftps", 990),
UNKNOWN_SERVICE(),
UNKNOWN_SERVICE(),
SERVICE("snmp", 161),
UNKNOWN_SERVICE(),
UNKNOWN_SERVICE(),
UNKNOWN_SERVICE(),
UNKNOWN_SERVICE(),
SERVICE("bgmp", 264),
SERVICE("echo", 7),
UNKNOWN_SERVICE(),
SERVICE("nnsp", 433),
SERVICE("submission", 587),
SERVICE("submissions", 465),
UNKNOWN_SERVICE(),
SERVICE("ptp-event", 319),
UNKNOWN_SERVICE(),
SERVICE("npp", 92),
UNKNOWN_SERVICE(),
SERVICE("https", 443),
SERVICE("http", 80),
UNKNOWN_SERVICE(),
SERVICE("telnet", 23),
SERVICE("tcpmux", 1),
UNKNOWN_SERVICE(),
SERVICE("lmtp", 24),
SERVICE("smtp", 25)
};
#undef SERVICE
#undef UNKNOWN_SERVICE
static really_inline uint8_t service_hash(uint64_t input, size_t length)
{
input = le64toh(input);
uint32_t input32 = (uint32_t)((input >> 32) ^ input);
return (((input32 * 139898079llu) >> 32) + length) & 0x3f;
}
nonnull((1,4))
static really_inline int32_t scan_service(
const char *data, size_t length, int32_t protocol, uint16_t *port)
{
uint8_t digit = (uint8_t)*data - '0';
static const int8_t zero_masks[48] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
(void)protocol;
if (digit > 9) {
uint64_t input0, input1;
static const uint64_t upper_mask = 0xdfdfdfdfdfdfdfdfllu;
static const uint64_t letter_mask = 0x4040404040404040llu;
memcpy(&input0, data, 8);
memcpy(&input1, data+8, 8);
uint64_t key = input0 & upper_mask;
uint64_t zero_mask0, zero_mask1;
const int8_t *zero_mask = &zero_masks[32 - (length & 0xf)];
memcpy(&zero_mask0, zero_mask, 8);
memcpy(&zero_mask1, zero_mask+8, 8);
uint8_t index = service_hash(key & zero_mask0, length);
assert(index < 64);
input0 |= (input0 & letter_mask) >> 1;
input0 &= zero_mask0;
input1 |= (input1 & letter_mask) >> 1;
input1 &= zero_mask1;
uint64_t name0, name1;
memcpy(&name0, services[index].key.name, 8);
memcpy(&name1, services[index].key.name+8, 8);
*port = services[index].port;
return (input0 == name0) &
(input1 == name1) &
(services[index].key.length == length);
}
return scan_int16(data, length, port);
}
#endif