0
0
mirror of https://github.com/hufrea/byedpi.git synced 2025-06-29 18:21:14 +00:00
byedpi/packets.c
2025-06-16 09:16:46 +03:00

586 lines
15 KiB
C

#include "packets.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
#define ANTOHS(data, i) \
(((uint16_t)data[i] << 8) + (uint8_t)data[i + 1])
#define SHTONA(data, i, x) \
data[i] = (uint8_t)((x) >> 8); \
data[i + 1] = ((x) & 0xff)
char tls_data[517] = {
"\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03\x03\x5f"
"\x6f\x2c\xed\x13\x22\xf8\xdc\xb2\xf2\x60\x48\x2d\x72"
"\x66\x6f\x57\xdd\x13\x9d\x1b\x37\xdc\xfa\x36\x2e\xba"
"\xf9\x92\x99\x3a\x20\xf9\xdf\x0c\x2e\x8a\x55\x89\x82"
"\x31\x63\x1a\xef\xa8\xbe\x08\x58\xa7\xa3\x5a\x18\xd3"
"\x96\x5f\x04\x5c\xb4\x62\xaf\x89\xd7\x0f\x8b\x00\x3e"
"\x13\x02\x13\x03\x13\x01\xc0\x2c\xc0\x30\x00\x9f\xcc"
"\xa9\xcc\xa8\xcc\xaa\xc0\x2b\xc0\x2f\x00\x9e\xc0\x24"
"\xc0\x28\x00\x6b\xc0\x23\xc0\x27\x00\x67\xc0\x0a\xc0"
"\x14\x00\x39\xc0\x09\xc0\x13\x00\x33\x00\x9d\x00\x9c"
"\x00\x3d\x00\x3c\x00\x35\x00\x2f\x00\xff\x01\x00\x01"
"\x75\x00\x00\x00\x16\x00\x14\x00\x00\x11\x77\x77\x77"
"\x2e\x77\x69\x6b\x69\x70\x65\x64\x69\x61\x2e\x6f\x72"
"\x67\x00\x0b\x00\x04\x03\x00\x01\x02\x00\x0a\x00\x16"
"\x00\x14\x00\x1d\x00\x17\x00\x1e\x00\x19\x00\x18\x01"
"\x00\x01\x01\x01\x02\x01\x03\x01\x04\x00\x10\x00\x0e"
"\x00\x0c\x02\x68\x32\x08\x68\x74\x74\x70\x2f\x31\x2e"
"\x31\x00\x16\x00\x00\x00\x17\x00\x00\x00\x31\x00\x00"
"\x00\x0d\x00\x2a\x00\x28\x04\x03\x05\x03\x06\x03\x08"
"\x07\x08\x08\x08\x09\x08\x0a\x08\x0b\x08\x04\x08\x05"
"\x08\x06\x04\x01\x05\x01\x06\x01\x03\x03\x03\x01\x03"
"\x02\x04\x02\x05\x02\x06\x02\x00\x2b\x00\x09\x08\x03"
"\x04\x03\x03\x03\x02\x03\x01\x00\x2d\x00\x02\x01\x01"
"\x00\x33\x00\x26\x00\x24\x00\x1d\x00\x20\x11\x8c\xb8"
"\x8c\xe8\x8a\x08\x90\x1e\xee\x19\xd9\xdd\xe8\xd4\x06"
"\xb1\xd1\xe2\xab\xe0\x16\x63\xd6\xdc\xda\x84\xa4\xb8"
"\x4b\xfb\x0e\x00\x15\x00\xac\x00\x00\x00\x00\x00\x00"
};
char http_data[43] = {
"GET / HTTP/1.1\r\n"
"Host: www.wikipedia.org\r\n\r\n"
};
char udp_data[64] = { 0 };
static char *strncasestr(const char *a, size_t as, const char *b, size_t bs)
{
for (const char *p = a; ; p++) {
p = memchr(p, *b, as - (p - a));
if (!p) {
return 0;
}
if ((p + bs) > (a + as)) {
return 0;
}
if (!strncasecmp(p, b, bs)) {
return (char *)p;
}
}
return 0;
}
static size_t find_tls_ext_offset(uint16_t type,
const char *data, size_t size, size_t skip)
{
if (size <= (skip + 2)) {
return 0;
}
uint16_t ext_len = ANTOHS(data, skip);
skip += 2;
if (ext_len < (size - skip)) {
size = ext_len + skip;
}
while ((skip + 4) < size) {
uint16_t epyt = ANTOHS(data, skip);
if (type == epyt) {
return skip;
}
uint16_t len = ANTOHS(data, skip + 2);
skip += (len + 4);
}
return 0;
}
static size_t find_ext_block(const char *data, size_t size)
{
if (size < 44) {
return 0;
}
uint8_t sid_len = data[43];
if (size < (44lu + sid_len + 2)) {
return 0;
}
uint16_t cip_len = ANTOHS(data, 44 + sid_len);
size_t skip = 44 + sid_len + 2 + cip_len + 2;
return skip > size ? 0 : skip;
}
static void merge_tls_records(char *buffer, ssize_t n)
{
if (n < 5) {
return;
}
uint16_t full_sz = 0;
uint16_t r_sz = ANTOHS(buffer, 3);
while (1) {
full_sz += r_sz;
if (5 + full_sz > n - 5
|| buffer[5 + full_sz] != *buffer) {
break;
}
r_sz = ANTOHS(buffer, 5 + full_sz + 3);
if (full_sz + 10 + r_sz > n) {
break;
}
memmove(buffer + 5 + full_sz,
buffer + 10 + full_sz, n - (10 + full_sz));
}
SHTONA(buffer, 3, full_sz);
SHTONA(buffer, 7, full_sz - 4);
}
static void copy_name(char *out, const char *name, size_t out_len)
{
for (size_t i = 0; i < out_len; i++) {
switch (name[i]) {
case '*':;
int r = rand() % (10 + 'z' - 'a' + 1);
out[i] = (r < 10 ? '0' : ('a' - 10)) + r;
break;
case '?':
out[i] = 'a' + (rand() % ('z' - 'a' + 1));
break;
case '#':
out[i] = '0' + (rand() % 10);
break;
default:
out[i] = name[i];
}
}
}
static int remove_tls_ext(char *buffer,
ssize_t n, size_t skip, uint16_t type)
{
ssize_t ext_offs = find_tls_ext_offset(type, buffer, n, skip);
if (!ext_offs) {
return 0;
}
uint16_t ext_sz = ANTOHS(buffer, ext_offs + 2);
ssize_t ext_end = ext_offs + 4 + ext_sz;
if (ext_end > n) {
return 0;
}
memmove(buffer + ext_offs, buffer + ext_end, n - ext_end);
return ext_sz + 4;
}
static int resize_ech_ext(char *buffer,
ssize_t n, size_t skip, int inc)
{
ssize_t ech_offs = find_tls_ext_offset(0xfe0d, buffer, n, skip);
if (!ech_offs) {
return 0;
}
uint16_t ech_sz = ANTOHS(buffer, ech_offs + 2);
ssize_t ech_end = ech_offs + 4 + ech_sz;
if (ech_sz < 12 || ech_end > n) {
return 0;
}
uint16_t enc_sz = ANTOHS(buffer, ech_offs + 4 + 6);
ssize_t pay_offs = ech_offs + 4 + 8 + enc_sz;
uint16_t pay_sz = ech_sz - (8 + enc_sz + 2);
if (pay_offs + 2 > n || pay_sz < -inc) {
return 0;
}
SHTONA(buffer, ech_offs + 2, ech_sz + inc);
SHTONA(buffer, pay_offs, pay_sz + inc);
memmove(buffer + ech_end + inc, buffer + ech_end, n - (ech_end + inc));
return inc;
}
static void resize_sni(char *buffer, ssize_t n,
ssize_t sni_offs, ssize_t sni_sz, ssize_t new_sz)
{
SHTONA(buffer, sni_offs + 2, new_sz + 5);
SHTONA(buffer, sni_offs + 4, new_sz + 3);
SHTONA(buffer, sni_offs + 7, new_sz);
ssize_t sni_end = sni_offs + 4 + sni_sz;
memmove(buffer + sni_end + new_sz - (sni_sz - 5), buffer + sni_end, n - sni_end);
}
int change_tls_sni(const char *host, char *buffer, ssize_t n, ssize_t nn)
{
merge_tls_records(buffer, n);
int avail = nn < n ? nn - n : 0;
uint16_t r_sz = ANTOHS(buffer, 3);
r_sz += avail;
size_t skip = find_ext_block(buffer, n);
if (!skip) {
return -1;
}
ssize_t sni_offs = find_tls_ext_offset(0x00, buffer, n, skip);
if (!sni_offs) {
return -1;
}
uint16_t new_sz = strlen(host);
uint16_t sni_sz = ANTOHS(buffer, sni_offs + 2);
if (sni_offs + 4 + sni_sz > n) {
return -1;
}
int diff = (int )new_sz - (sni_sz - 5);
avail -= diff;
if (diff < 0 && avail > 0) {
resize_sni(buffer, n, sni_offs, sni_sz, new_sz);
diff = 0;
}
if (avail) {
avail -= resize_ech_ext(buffer, n, skip, avail);
}
uint16_t exts[] = {
0x0015, // padding
0x0031, // post_handshake_auth
0x0010, // ALPN
0x001c, // record_size_limit
0x0023, // session_ticket
0x0005, // status_request
0x0022, // delegated_credentials
0x0012, // signed_certificate_timestamp
0x001b, // compress_certificate
0
};
for (uint16_t *e = exts; avail && avail < 4; e++) {
if (!*e) {
return -1;
}
avail += remove_tls_ext(buffer, n, skip, *e);
}
if (!(sni_offs = find_tls_ext_offset(0x00, buffer, n, skip))) {
return -1;
}
if (diff) {
resize_sni(buffer, n, sni_offs, sni_sz, new_sz);
}
copy_name(buffer + sni_offs + 9, host, new_sz);
if (avail >= 4) {
avail += remove_tls_ext(buffer, n, skip, 0x0015);
SHTONA(buffer, 5 + r_sz - avail, 0x0015);
SHTONA(buffer, 5 + r_sz - avail + 2, avail - 4);
memset(buffer + 5 + r_sz - avail + 4, 0, avail - 4);
}
SHTONA(buffer, 3, r_sz);
SHTONA(buffer, 7, r_sz - 4);
SHTONA(buffer, skip, 5 + r_sz - skip - 2);
return 0;
}
bool is_tls_chello(const char *buffer, size_t bsize)
{
return (bsize > 5 &&
ANTOHS(buffer, 0) == 0x1603 &&
buffer[5] == 0x01);
}
int parse_tls(const char *buffer, size_t bsize, char **hs)
{
if (!is_tls_chello(buffer, bsize)) {
return 0;
}
size_t skip = find_ext_block(buffer, bsize);
if (!skip) {
return 0;
}
size_t sni_offs = find_tls_ext_offset(0x00, buffer, bsize, skip);
if (!sni_offs || (sni_offs + 12) >= bsize) {
return 0;
}
uint16_t len = ANTOHS(buffer, sni_offs + 7);
if ((sni_offs + 9 + len) > bsize) {
return 0;
}
*hs = (char *)&buffer[sni_offs + 9];
return len;
}
bool is_http(const char *buffer, size_t bsize)
{
if (bsize < 16 || *buffer > 'T' || *buffer < 'C') {
return 0;
}
const char *methods[] = {
"HEAD", "GET", "POST", "PUT", "DELETE",
"OPTIONS", "CONNECT", "TRACE", "PATCH", 0
};
for (const char **m = methods; *m; m++) {
if (strncmp(buffer, *m, strlen(*m)) == 0) {
return 1;
}
}
return 0;
}
int parse_http(const char *buffer, size_t bsize, char **hs, uint16_t *port)
{
const char *host = buffer, *l_end;
const char *buff_end = buffer + bsize;
if (!is_http(buffer, bsize)) {
return 0;
}
if (!(host = strncasestr(buffer, bsize, "\nHost:", 6))) {
return 0;
}
host += 6;
for (; host < buff_end && *host == ' '; host++);
if (!(l_end = memchr(host, '\n', buff_end - host))) {
return 0;
}
for (; isspace((unsigned char) *(l_end - 1)); l_end--);
const char *h_end = l_end - 1;
while (isdigit((unsigned char) *--h_end));
if (*h_end != ':') {
if (port) *port = 80;
h_end = l_end;
}
else if (port) {
char *end;
long i = strtol(h_end + 1, &end, 10);
if (i <= 0 || end != l_end || i > 0xffff)
return 0;
*port = i;
}
if (*host == '[') {
if (*--h_end != ']')
return 0;
host++;
}
*hs = (char *)host;
return h_end - host;
}
static int get_http_code(const char *b, size_t n)
{
if (n < 13 || strncmp(b, "HTTP/1.", 7)) {
return 0;
}
if (!memchr(b + 12, '\n', n - 12)) {
return 0;
}
char *e;
long num = strtol(b + 9, &e, 10);
if (num < 100 || num > 511 || !isspace((unsigned char) *e)) {
return 0;
}
return (int )num;
}
bool is_http_redirect(
const char *req, size_t qn, const char *resp, size_t sn)
{
char *host = 0, *location;
int len = parse_http(req, qn, &host, 0);
if (len <= 0 || sn < 29) {
return 0;
}
int code = get_http_code(resp, sn);
if (code > 308 || code < 300) {
return 0;
}
if (!(location = strncasestr(resp, sn, "\nLocation:", 10))
|| ((location += 11) + 8) >= (resp + sn)) {
return 0;
}
char *l_end = memchr(location, '\n', sn - (location - resp));
if (!l_end) {
return 0;
}
for (; isspace((unsigned char) *(l_end - 1)); l_end--);
if ((l_end - location) > 7) {
if (!strncmp(location, "http://", 7)) {
location += 7;
}
else if (!strncmp(location, "https://", 8)) {
location += 8;
}
}
char *le = memchr(location, '/', l_end - location);
if (!le) le = l_end;
char *he = host + len, *h = he;
while (h != host && *(--h - 1) != '.');
while (h != host && *(--h - 1) != '.');
return ((le - location) < (he - h))
|| memcmp(le - (he - h), h, he - h) != 0;
}
bool neq_tls_sid(const char *req, size_t qn, const char *resp, size_t sn)
{
if (qn < 75 || sn < 75) {
return 0;
}
if (!is_tls_chello(req, qn)
|| ANTOHS(resp, 0) != 0x1603) {
return 0;
}
uint8_t sid_len = req[43];
size_t skip = 44 + sid_len + 3;
if (!find_tls_ext_offset(0x2b, resp, sn, skip)) {
return 0;
}
if (req[43] != resp[43]) {
return 1;
}
return memcmp(req + 44, resp + 44, sid_len);
}
bool is_tls_shello(const char *buffer, size_t bsize)
{
return (bsize > 5 &&
ANTOHS(buffer, 0) == 0x1603 &&
buffer[5] == 0x02);
}
/*
bool is_dns_req(char *buffer, size_t n)
{
if (n < 12) {
return 0;
}
return !memcmp(buffer + 2, "\1\0\0\1\0\0\0\0\0\0", 10);
}
bool is_quic_initial(char *buffer, size_t bsize)
{
return (bsize > 64 && (buffer[0] & 0xc0) == 0xc0);
}
*/
int mod_http(char *buffer, size_t bsize, int m)
{
char *host = 0, *par;
int hlen = parse_http(buffer, bsize, &host, 0);
if (!hlen)
return -1;
for (par = host - 1; *par != ':'; par--) {}
par -= 4;
if (m & MH_HMIX) {
par[0] = tolower((unsigned char) par[0]);
par[1] = toupper((unsigned char) par[1]);
par[3] = toupper((unsigned char) par[3]);
}
if (m & MH_DMIX) {
for (int i = 0; i < hlen; i += 2) {
host[i] = toupper((unsigned char)host[i]);
}
}
if (m & MH_SPACE) {
for (; !isspace((unsigned char) *(host + hlen)); hlen++) {}
int sc = host - (par + 5);
memmove(par + 5, host, hlen);
memset(par + 5 + hlen, '\t', sc);
}
return 0;
}
int part_tls(char *buffer, size_t bsize, ssize_t n, long pos)
{
if ((n < 3) || (bsize - n < 5) ||
(pos < 0) || (pos + 5 > n)) {
return 0;
}
uint16_t r_sz = ANTOHS(buffer, 3);
if (r_sz < pos) {
return n;
}
memmove(buffer + 5 + pos + 5, buffer + 5 + pos, n - (5 + pos));
memcpy(buffer + 5 + pos, buffer, 3);
SHTONA(buffer, 3, pos);
SHTONA(buffer, 5 + pos + 3, r_sz - pos);
return 5;
}
static void gen_rand_array(char *out, size_t len)
{
for (; len; len--, out++) {
uint8_t c = rand() % 256;
*((uint8_t *)out) = c;
}
}
void randomize_tls(char *buffer, ssize_t n)
{
if (n < 44) {
return;
}
uint8_t sid_len = buffer[43];
if (n < (44l + sid_len + 2)) {
return;
}
gen_rand_array(buffer + 11, 32);
gen_rand_array(buffer + 44, sid_len);
size_t skip = find_ext_block(buffer, n);
if (!skip) {
return;
}
ssize_t ks_offs = find_tls_ext_offset(0x0033, buffer, n, skip);
if (!ks_offs || ks_offs + 6 >= n) {
return;
}
int ks_sz = ANTOHS(buffer, ks_offs + 2);
if (ks_offs + 4 + ks_sz > n) {
return;
}
ssize_t g_offs = ks_offs + 4 + 2;
while (g_offs + 4 < ks_offs + 4 + ks_sz) {
uint16_t g_sz = ANTOHS(buffer, g_offs + 2);
if (ks_offs + 4 + g_sz > n) {
return;
}
gen_rand_array(buffer + g_offs + 4, g_sz);
g_offs += 4 + g_sz;
}
}