2024-08-07 11:25:26 +00:00
|
|
|
#include "packets.h"
|
|
|
|
|
2023-06-03 19:52:10 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
2024-04-08 20:09:51 +00:00
|
|
|
#include <stdbool.h>
|
2023-06-03 19:52:10 +00:00
|
|
|
#include <string.h>
|
2024-08-12 17:38:14 +00:00
|
|
|
#include <strings.h>
|
2024-02-18 20:20:52 +00:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include <winsock2.h>
|
|
|
|
#else
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#endif
|
2023-06-03 19:52:10 +00:00
|
|
|
|
|
|
|
#define ANTOHS(data, i) \
|
|
|
|
(uint16_t)((data[i] << 8) + (uint8_t)data[i + 1])
|
|
|
|
|
2024-08-05 19:46:39 +00:00
|
|
|
#define SHTONA(data, i, x) \
|
2024-08-06 10:54:07 +00:00
|
|
|
data[i] = (uint8_t)((x) >> 8); \
|
|
|
|
data[i + 1] = ((x) & 0xff)
|
2024-08-05 19:46:39 +00:00
|
|
|
|
2023-06-03 19:52:10 +00:00
|
|
|
|
|
|
|
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"
|
|
|
|
};
|
|
|
|
|
2024-07-29 09:26:42 +00:00
|
|
|
char udp_data[64] = { 0 };
|
|
|
|
|
2023-06-03 19:52:10 +00:00
|
|
|
|
2024-04-08 20:09:51 +00:00
|
|
|
char *strncasestr(char *a, size_t as, char *b, size_t bs)
|
2024-04-03 19:51:02 +00:00
|
|
|
{
|
|
|
|
for (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 p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-23 19:45:42 +00:00
|
|
|
size_t find_tls_ext_offset(uint16_t type,
|
|
|
|
char *data, size_t size, size_t skip)
|
2023-06-03 19:52:10 +00:00
|
|
|
{
|
2024-04-23 19:45:42 +00:00
|
|
|
if (size <= (skip + 2)) {
|
2023-06-03 19:52:10 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2024-04-23 19:45:42 +00:00
|
|
|
uint16_t ext_len = ANTOHS(data, skip);
|
|
|
|
skip += 2;
|
2023-06-03 19:52:10 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-23 19:45:42 +00:00
|
|
|
size_t chello_ext_offset(uint16_t type, char *data, size_t size)
|
|
|
|
{
|
|
|
|
if (size < 44) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
uint8_t sid_len = data[43];
|
|
|
|
if (size < 44 + 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 find_tls_ext_offset(type, data, size, skip);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-03-02 16:13:55 +00:00
|
|
|
int change_tls_sni(const char *host, char *buffer, size_t bsize)
|
2023-06-03 19:52:10 +00:00
|
|
|
{
|
2024-04-08 20:09:51 +00:00
|
|
|
size_t sni_offs, pad_offs;
|
2023-06-03 19:52:10 +00:00
|
|
|
|
2024-04-23 19:45:42 +00:00
|
|
|
if (!(sni_offs = chello_ext_offset(0x00, buffer, bsize))) {
|
2023-06-03 19:52:10 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2024-04-23 19:45:42 +00:00
|
|
|
if (!(pad_offs = chello_ext_offset(0x15, buffer, bsize))) {
|
2023-06-03 19:52:10 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
char *sni = &buffer[sni_offs];
|
|
|
|
char *pad = &buffer[pad_offs];
|
|
|
|
|
|
|
|
uint16_t old_sz = ANTOHS(buffer, sni_offs + 2) - 5;
|
|
|
|
uint16_t free_sz = ANTOHS(buffer, pad_offs + 2);
|
|
|
|
uint16_t new_sz = strlen(host);
|
|
|
|
|
|
|
|
ssize_t diff = new_sz - old_sz;
|
|
|
|
|
|
|
|
if ((free_sz != (bsize - pad_offs - 4))
|
|
|
|
|| free_sz < diff) {
|
|
|
|
return -1;
|
|
|
|
}
|
2024-08-05 19:46:39 +00:00
|
|
|
SHTONA(sni, 2, old_sz + diff + 5);
|
|
|
|
SHTONA(sni, 4, old_sz + diff + 3);
|
|
|
|
SHTONA(sni, 7, old_sz + diff);
|
|
|
|
SHTONA(pad, 2, free_sz - diff);
|
2023-06-03 19:52:10 +00:00
|
|
|
|
|
|
|
char *host_end = sni + 9 + old_sz;
|
|
|
|
int oth_sz = bsize - (sni_offs + 9 + old_sz);
|
|
|
|
|
|
|
|
memmove(host_end + diff, host_end, oth_sz);
|
|
|
|
memcpy(sni + 9, host, new_sz);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-23 05:47:27 +00:00
|
|
|
bool is_tls_chello(char *buffer, size_t bsize)
|
|
|
|
{
|
|
|
|
return (bsize > 5 &&
|
|
|
|
ANTOHS(buffer, 0) == 0x1603 &&
|
|
|
|
buffer[5] == 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-06-03 19:52:10 +00:00
|
|
|
int parse_tls(char *buffer, size_t bsize, char **hs)
|
|
|
|
{
|
2024-04-23 05:47:27 +00:00
|
|
|
if (!is_tls_chello(buffer, bsize)) {
|
2023-06-03 19:52:10 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2024-04-23 19:45:42 +00:00
|
|
|
size_t sni_offs = chello_ext_offset(0x00, buffer, bsize);
|
2023-06-03 19:52:10 +00:00
|
|
|
|
|
|
|
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 = &buffer[sni_offs + 9];
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-08 20:09:51 +00:00
|
|
|
bool is_http(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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-06-03 19:52:10 +00:00
|
|
|
int parse_http(char *buffer, size_t bsize, char **hs, uint16_t *port)
|
|
|
|
{
|
|
|
|
char *host = buffer, *h_end;
|
2024-04-03 19:51:02 +00:00
|
|
|
char *buff_end = buffer + bsize;
|
2023-06-03 19:52:10 +00:00
|
|
|
|
2024-04-08 20:09:51 +00:00
|
|
|
if (!is_http(buffer, bsize)) {
|
2023-06-03 19:52:10 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2024-04-03 19:51:02 +00:00
|
|
|
host = strncasestr(buffer, bsize, "\nHost:", 6);
|
2024-04-08 20:09:51 +00:00
|
|
|
if (!host) {
|
|
|
|
return 0;
|
|
|
|
}
|
2024-04-03 19:51:02 +00:00
|
|
|
host += 6;
|
|
|
|
|
2024-08-19 12:35:13 +00:00
|
|
|
while ((buff_end - host) > 0 && isblank((unsigned char) *host)) {
|
2023-06-03 19:52:10 +00:00
|
|
|
host++;
|
|
|
|
}
|
2024-04-03 19:51:02 +00:00
|
|
|
char *l_end = memchr(host, '\n', buff_end - host);
|
2023-06-03 19:52:10 +00:00
|
|
|
if (!l_end) {
|
|
|
|
return 0;
|
|
|
|
}
|
2024-08-19 12:35:13 +00:00
|
|
|
for (; isspace((unsigned char) *(l_end - 1)); l_end--) {}
|
2023-06-03 19:52:10 +00:00
|
|
|
|
2024-08-19 12:35:13 +00:00
|
|
|
if (!(isdigit((unsigned char) *(l_end - 1))))
|
2023-06-03 19:52:10 +00:00
|
|
|
h_end = 0;
|
2024-02-18 20:20:52 +00:00
|
|
|
else {
|
|
|
|
char *h = host;
|
|
|
|
h_end = 0;
|
|
|
|
do {
|
|
|
|
h = memchr(h, ':', l_end - h);
|
2024-02-29 22:27:04 +00:00
|
|
|
if (h) {
|
|
|
|
h_end = h;
|
|
|
|
h++;
|
|
|
|
}
|
|
|
|
} while (h && h < l_end);
|
2024-02-18 20:20:52 +00:00
|
|
|
}
|
2023-06-03 19:52:10 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
*hs = host;
|
|
|
|
return h_end - host;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-08 20:09:51 +00:00
|
|
|
int get_http_code(char *b, size_t n)
|
2024-04-03 19:51:02 +00:00
|
|
|
{
|
|
|
|
if (n < 13) return 0;
|
|
|
|
if (strncmp(b, "HTTP/1.", 7)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!memchr(b + 13, '\n', n)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
char *e;
|
|
|
|
long num = strtol(b + 9, &e, 10);
|
2024-08-19 12:35:13 +00:00
|
|
|
if (num < 100 || num > 511 || !isspace((unsigned char) *e)) {
|
2024-04-03 19:51:02 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return (int )num;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-08 20:09:51 +00:00
|
|
|
bool is_http_redirect(char *req, size_t qn, char *resp, size_t sn)
|
2024-04-03 19:51:02 +00:00
|
|
|
{
|
|
|
|
char *host = 0;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
char *location = strncasestr(resp, sn, "\nLocation:", 10);
|
|
|
|
if (!location) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
location += 11;
|
|
|
|
|
|
|
|
if ((location + 8) >= (resp + sn)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
char *l_end = memchr(location, '\n', sn - (location - resp));
|
|
|
|
if (!l_end) {
|
|
|
|
return 0;
|
|
|
|
}
|
2024-08-19 12:35:13 +00:00
|
|
|
for (; isspace((unsigned char) *(l_end - 1)); l_end--) {}
|
2024-04-03 19:51:02 +00:00
|
|
|
|
|
|
|
if ((l_end - location) > 7) {
|
|
|
|
if (!strncmp(location, "http://", 7)) {
|
|
|
|
location += 7;
|
|
|
|
}
|
|
|
|
else if (!strncmp(location, "https://", 8)) {
|
|
|
|
location += 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
char *e = memchr(location, '/', l_end - location);
|
|
|
|
if (!e) e = l_end;
|
|
|
|
|
|
|
|
for (; (e - location) > len; location++) {
|
|
|
|
location = memchr(location, '.', e - location);
|
|
|
|
if (!location) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (; len > (e - location); host++) {
|
|
|
|
char *p = memchr(host, '.', len);
|
|
|
|
if (!p) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
len -= (host - p) + 1;
|
|
|
|
host = p;
|
|
|
|
}
|
|
|
|
return (((e - location) != len)
|
|
|
|
|| strncmp(host, location, len));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-08 20:09:51 +00:00
|
|
|
bool neq_tls_sid(char *req, size_t qn, char *resp, size_t sn)
|
2024-04-03 19:51:02 +00:00
|
|
|
{
|
|
|
|
if (qn < 75 || sn < 75) {
|
|
|
|
return 0;
|
|
|
|
}
|
2024-04-23 05:47:27 +00:00
|
|
|
if (!is_tls_chello(req, qn)
|
2024-04-03 19:51:02 +00:00
|
|
|
|| ANTOHS(resp, 0) != 0x1603) {
|
|
|
|
return 0;
|
|
|
|
}
|
2024-04-23 19:45:42 +00:00
|
|
|
uint8_t sid_len = req[43];
|
|
|
|
size_t skip = 44 + sid_len + 3;
|
|
|
|
|
|
|
|
if (!find_tls_ext_offset(0x2b, resp, sn, skip)) {
|
|
|
|
return 0;
|
|
|
|
}
|
2024-04-03 19:51:02 +00:00
|
|
|
if (req[43] != resp[43]) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return memcmp(req + 44, resp + 44, sid_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-08-13 14:00:03 +00:00
|
|
|
bool is_tls_shello(char *buffer, size_t bsize)
|
|
|
|
{
|
|
|
|
return (bsize > 5 &&
|
|
|
|
ANTOHS(buffer, 0) == 0x1603 &&
|
|
|
|
buffer[5] == 0x02);
|
2024-04-03 19:51:02 +00:00
|
|
|
}
|
|
|
|
|
2024-04-25 22:15:02 +00:00
|
|
|
/*
|
2024-04-23 05:47:27 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-08-04 16:26:18 +00:00
|
|
|
bool is_quic_initial(char *buffer, size_t bsize)
|
2024-04-23 05:47:27 +00:00
|
|
|
{
|
|
|
|
return (bsize > 64 && (buffer[0] & 0xc0) == 0xc0);
|
|
|
|
}
|
2024-04-25 22:15:02 +00:00
|
|
|
*/
|
2024-04-23 05:47:27 +00:00
|
|
|
|
2023-06-03 19:52:10 +00:00
|
|
|
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) {
|
2024-08-19 12:35:13 +00:00
|
|
|
par[0] = tolower((unsigned char) par[0]);
|
|
|
|
par[1] = toupper((unsigned char) par[1]);
|
|
|
|
par[3] = toupper((unsigned char) par[3]);
|
2023-06-03 19:52:10 +00:00
|
|
|
}
|
|
|
|
if (m & MH_DMIX) {
|
|
|
|
for (int i = 0; i < hlen; i += 2) {
|
2024-08-19 12:35:13 +00:00
|
|
|
host[i] = toupper((unsigned char)host[i]);
|
2023-06-03 19:52:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m & MH_SPACE) {
|
2024-08-19 12:35:13 +00:00
|
|
|
for (; !isspace((unsigned char) *(host + hlen)); hlen++) {}
|
2023-06-03 19:52:10 +00:00
|
|
|
int sc = host - (par + 5);
|
|
|
|
memmove(par + 5, host, hlen);
|
|
|
|
memset(par + 5 + hlen, '\t', sc);
|
|
|
|
}
|
|
|
|
return 0;
|
2023-10-10 18:24:46 +00:00
|
|
|
}
|
2024-02-18 14:19:11 +00:00
|
|
|
|
|
|
|
|
2024-04-08 20:09:51 +00:00
|
|
|
int part_tls(char *buffer, size_t bsize, ssize_t n, long pos)
|
2024-02-18 14:19:11 +00:00
|
|
|
{
|
|
|
|
if ((n < 3) || (bsize - n < 5) ||
|
|
|
|
(pos < 0) || (pos + 5 > n)) {
|
2024-03-04 12:30:23 +00:00
|
|
|
return 0;
|
2024-02-18 14:19:11 +00:00
|
|
|
}
|
|
|
|
uint16_t r_sz = ANTOHS(buffer, 3);
|
2024-02-19 19:01:25 +00:00
|
|
|
if (r_sz < pos) {
|
|
|
|
return n;
|
|
|
|
}
|
2024-02-18 14:19:11 +00:00
|
|
|
memmove(buffer + 5 + pos + 5, buffer + 5 + pos, n - (5 + pos));
|
|
|
|
memcpy(buffer + 5 + pos, buffer, 3);
|
|
|
|
|
2024-08-05 19:46:39 +00:00
|
|
|
SHTONA(buffer, 3, pos);
|
|
|
|
SHTONA(buffer, 5 + pos + 3, r_sz - pos);
|
2024-03-04 12:30:23 +00:00
|
|
|
return 5;
|
2024-02-18 14:19:11 +00:00
|
|
|
}
|