Добавлены проверки MAC-адреса и команд создания/удаления символической ссылки

This commit is contained in:
Alexander Zhirov 2022-08-18 11:03:28 +03:00
parent 755296ad6d
commit fcc3f73807
10 changed files with 178 additions and 19 deletions

View File

@ -41,5 +41,5 @@ a836823eda80e43b8914b7b045b91703faded83d2b1482a0d17f0fb903cbc0ce17dd9e0c06a2f6e3
8a5de40dde8a5e569fce4309e01341a77a4e36cdcb5fe602948d5b34ee2646bd83840158d7d61a45c17e71cc893f3e9bd04a38ebcc7a6a8fff98f46a50d74e96 in.tftpd.confd 8a5de40dde8a5e569fce4309e01341a77a4e36cdcb5fe602948d5b34ee2646bd83840158d7d61a45c17e71cc893f3e9bd04a38ebcc7a6a8fff98f46a50d74e96 in.tftpd.confd
40127e7ce276a2bc015255dbeef2665bfe8ff006b1e1d8fb79797e946d6030fd74606cffe0bea11eaad276a693f223faaaf1c1ccb5f276b40fdad40b366172b7 fix-common.patch 40127e7ce276a2bc015255dbeef2665bfe8ff006b1e1d8fb79797e946d6030fd74606cffe0bea11eaad276a693f223faaaf1c1ccb5f276b40fdad40b366172b7 fix-common.patch
736e205531c25da2a1c3ad0311c2be6a95a2778ecbce976be057c3bf2b8da65cccce9e7013deded61217a61f32dd18bdea311807504d60cadbd16687471deb70 trq.patch 736e205531c25da2a1c3ad0311c2be6a95a2778ecbce976be057c3bf2b8da65cccce9e7013deded61217a61f32dd18bdea311807504d60cadbd16687471deb70 trq.patch
929749b3e2a297197b2be124df6364fad38f226d54fe6f006dc257457db5a247f6f5006063479b09ee20c7d8de7174e31db3d54b5956f841eee0f725edf31f3d trq.c 314eea07339e7c8605a69db65638aacfb488077f39b127bdc81369202d0edae6545a456705cebe08fde3729293b7609892a09d91ec2f7dc93b63d693b10ff833 trq.c
29cc72f3197bcaea4a88dace5c91d53dad5d20a397752198e601e2ed83fdb66fca50a5b4b03c4d3033ebd7a0be1e90801a692c514733412d8d96cafde26e0837 trq.h" 29cc72f3197bcaea4a88dace5c91d53dad5d20a397752198e601e2ed83fdb66fca50a5b4b03c4d3033ebd7a0be1e90801a692c514733412d8d96cafde26e0837 trq.h"

115
README.md Normal file
View File

@ -0,0 +1,115 @@
# tftp-hpa
- [Описание](#описание)
- [Пример запроса на `php`](#пример-запроса-на-php)
- [Сборка пакета в Docker](#сборка-пакета-в-docker)
- [Безопасность](#безопасность)
![protocol](img/protocol.png)
## Описание
К [стандартным](http://isp.vsi.ru/library/Networking/TCPIPIllustrated/tftp_tri.htm) `opcodes` `RRQ` и `WRQ` был добавлен `TRQ` (*Thinstation Request*) со значением `6`, позволяющий создать символическую ссылку на файл-загрузчик для PXE-сервера.
Структура `filename` принимаемая TFTP-сервером состоит из частей, разделённая `;`:
```sh
01-<mac-address>;<command>;<source-file>
```
где
- `01` - указывается как префикс MAC-адреса тонкого клиента
- `mac-address` - MAC-адрес тонкого клиента в нижнем регистре, разделённого `-`, например `ff-ff-ff-ff-ff-ff`
- `command` - команда (`cr`/`rm`) для создания/удаления символической ссылки на файл
- `source-file` - основной файл, на который необходимо создать символическую ссылку
Символическая ссылка создаётся в директории `mac.cfg` с правами `drwxrwxrwx`, расположенной в корневой директории TFTP сервера.
Например, структура `filename` создания симолической ссылки на файл `thinstation`:
```sh
01-ff-ff-ff-ff-ff-ff;cr;thinstation
```
Удаление символической ссылки:
```sh
01-ff-ff-ff-ff-ff-ff;rm
```
Структура каталога `tftpboot`:
```sh
.
└── tftpboot
   └── [drwxrwxrwx] mac.cfg
├── 01-ff-ff-ff-ff-ff-ff -> thinstation
   └── thinstation
```
## Пример запроса на PHP
Создание пакета на `php` для создания символической ссылки, отправляемого на TFTP-сервер:
```php
$opcode = 6; // TRQ opcode
$request = '01-ff-ff-ff-ff-ff-ff;cr;thinstation';
$mode = 'octet';
$ip = '192.168.1.1';
$port = 69;
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
$package = chr(0) . chr($opcode) . $request . chr(0) . $mode . chr(0);
socket_sendto($sock, $package, strlen($package), MSG_EOF, $ip, $port);
socket_close($sock);
```
## Сборка пакета в Docker
Склонировать репозиторий в удобное место:
```sh
git clone https://git.zhirov.website/alexander/tftp-hpa.git tftp-hpa
```
Войти в оболочку `alpine` для сборки пакета запустив `docker` командой:
```sh
docker run --rm -it -v $PWD/tftp-hpa:/home/packager/reposerve/main/tftp-hpa alpine:latest sh
```
Установить инструменты разработчика:
```sh
apk add sudo build-base alpine-sdk
```
Cоздать пользователя `packager` и добавьте его в список sudo
```sh
adduser -D packager
addgroup packager abuild
echo 'packager ALL=(ALL) NOPASSWD:ALL' >/etc/sudoers.d/packager
```
Войти под созданным пользователем `packager`:
```sh
sudo -u packager sh
```
Сгенерировать ключи:
```sh
abuild-keygen -a -i
```
Собрать пакет:
```sh
cd /home/packager/reposerve/main/tftp-hpa
REPODEST=~/packages/latest abuild -r
```
Для установки в других экземплярах `alpine` возможно понадобятся сгенерированные ранее ключи для сборки пакета (`/home/packager/.abuild/{*.rsa,*.rsa.pub}`).
## Безопасность
Отсутствует проверка на источник запроса, так как сформировать запрос на создание/удаление символической ссылки выполняется в произвольной форме.

BIN
img/protocol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
package/APKINDEX.tar.gz Normal file

Binary file not shown.

1
package/key/abuild.conf Normal file
View File

@ -0,0 +1 @@
PACKAGER_PRIVKEY="/home/packager/.abuild/packager-62fdf15d.rsa"

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA7X2j1S7QDmBUQLyzytZ2GjpYYEgOq7drzyaGeYIL2GY8rm2C
ytHQxeo2OfSUESUb/sad9kBw2NXlA1AOi/9maES25+IxOGa0koBkRm8jmPPm5Wbe
h1zqWHIjNH3uaiPPZvgFqUL/boeuRDQ4cDjr8R3eHSAED+SwmnvSiJCFeMjGfHId
uc9k/L7F0l4RSs50WHFwzNXB4xebJnbwCUN1c/W4aBCew0k1vzXxVuwe2YpUoeGY
o0veNvKX5xKKNMhC6EJoVmjBDcXCOtN+F3GNvNaUO6JslC7nYAWxK5/CRUuICZaj
s5/+GaO7/rPC8vGnMGDw9aTOH7bISN+zHDHq9wIDAQABAoIBAQDKPSDEDO5OH8f/
rPIqfEDsitzxeMtNfZAIQpVnadAugrmQDF/B2bTApXdyGQ3yH7jcWETyC+RNMrCo
Boesvlx11HYxt1QU5JlG3KEHveMBgEoS9mvvt7c0hFXogIkDx+T5maIwhoZAmLhV
Cmc5Ya/Cj52zDa2H30Zo96LMes2+kQ9IPpNFJevY1pBB2d+B9Tg6QOHLxSFXdJ4H
+XXmtAFUvO5bEAicsRlMvav7FPPK3o7i5FQ6JCL5nDNGDbHw72WxKDpbqlhZsFN9
oIyx++4Vu94H3BE0b8UDcTQyF+V3TSjn9OXBKNsb8VcVt75HWw7A8iaSIJctofMh
v8jDRt/pAoGBAPgpwEEeJFLUOlH35IPOZ2MolnqnUzbwPW8VnzLk1PA9/8pqU8Xh
YljgOcI3hK755Pz3HTB8hQor6yTTR7lzIHGp3zGhAWw46qiqBzJVHzTGfols9i8b
2cx8ZUHkad4VpaB6KtKpfArfTkEk0QPNRFEYjg05mppqhfyG9bDV+HRrAoGBAPT9
nBuEN98FzhyBJBWtTCdnkJh8Eqw2HzI5OHGwVCdYv3GnapWIHHVLr2N4s2+sL7xP
WuKfyosVDj5WrANmQtkwyFxkVBapptV8Bw84lAGuVOfea3c7lgA6Zj15ldiFMbHU
0LhBYTfqZu7+3OhHbV+nCrY/cexqGYD8JuePFSalAoGBANXpx1taTB1J62u0rzoe
tWf4GJ5plYWJ2KrkjHImZpcgGlm1BblQ6qGJxr/vc2QQ7J5RtMuSymtWKD96EB1/
a7wOneH902giN8RjrAhq75dicrirQBqjez6VDAOcjNVu+3I1XKxyhAYrLx1gSvtn
+TeeXvRvbyEkKZLgEvD3wE85AoGANiPxorcWbcfno676XXv9r1uYvcn1im8vd7bj
fWRdRJC9Rg2cZU0+FMHUEaRz6wLfTbsvt5NefFv72NTokJvBvCOms5xMZPG698S/
/qIfOzvecZtanm/hl01QmNdMwRu2PrlsIrv4ExZPBxP1l7NpPVE58cqVj4xm9HVE
17lsEC0CgYAWgcAkEr2mBQ7BtOJZmmweDRe2q6VOuPVgVzS3knzaN59FvCNeImU2
Zmuz0fhiW1KSefOZ98AQA3Hl+uE06FEN5cJrI2qSnOkTJqyTc/x1Gi/rZLA0BWby
Th3eMMcnd7cpc8WDT5Dfg6YIwlw+OEIEXuxDzhIDej1BJDynR3izEA==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7X2j1S7QDmBUQLyzytZ2
GjpYYEgOq7drzyaGeYIL2GY8rm2CytHQxeo2OfSUESUb/sad9kBw2NXlA1AOi/9m
aES25+IxOGa0koBkRm8jmPPm5Wbeh1zqWHIjNH3uaiPPZvgFqUL/boeuRDQ4cDjr
8R3eHSAED+SwmnvSiJCFeMjGfHIduc9k/L7F0l4RSs50WHFwzNXB4xebJnbwCUN1
c/W4aBCew0k1vzXxVuwe2YpUoeGYo0veNvKX5xKKNMhC6EJoVmjBDcXCOtN+F3GN
vNaUO6JslC7nYAWxK5/CRUuICZajs5/+GaO7/rPC8vGnMGDw9aTOH7bISN+zHDHq
9wIDAQAB
-----END PUBLIC KEY-----

BIN
package/tftp-hpa-5.2-r4.apk Normal file

Binary file not shown.

Binary file not shown.

View File

@ -14,6 +14,7 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <regex.h>
void ts_free(ts_args *args) void ts_free(ts_args *args)
{ {
@ -29,7 +30,6 @@ void ts_free(ts_args *args)
free(args->path_src); free(args->path_src);
if (args->command) if (args->command)
free(args->path_dst); free(args->path_dst);
free(args); free(args);
} }
} }
@ -41,23 +41,17 @@ static char* ts_concat_path(const char *file)
syslog(LOG_NOTICE, "TRQ Invalid value file (ts_concat_path)\n"); syslog(LOG_NOTICE, "TRQ Invalid value file (ts_concat_path)\n");
exit(3); exit(3);
} }
const char *path_mac = "mac.cfg/"; const char *path_mac = "mac.cfg/";
size_t len1 = strlen(path_mac); size_t len1 = strlen(path_mac);
size_t len2 = strlen(file); size_t len2 = strlen(file);
char *result = (char*) malloc(sizeof(char) * (len1 + len2 + 1)); char *result = (char*) malloc(sizeof(char) * (len1 + len2 + 1));
if (!result) if (!result)
{ {
syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_concat_path)\n"); syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_concat_path)\n");
exit(3); exit(3);
} }
strncpy(result, path_mac, (len1 + 1)); strncpy(result, path_mac, (len1 + 1));
strncpy(result + len1, file, (len2 + 1)); strncpy(result + len1, file, (len2 + 1));
return result; return result;
} }
@ -65,7 +59,6 @@ static char* ts_copy_string(const char *string)
{ {
if (!string) if (!string)
return NULL; return NULL;
int len = strlen(string); int len = strlen(string);
char *tmp = (char*) calloc(1, sizeof(char) * (len + 1)); char *tmp = (char*) calloc(1, sizeof(char) * (len + 1));
if (!tmp) if (!tmp)
@ -74,7 +67,6 @@ static char* ts_copy_string(const char *string)
exit(3); exit(3);
} }
strncpy(tmp, string, (len + 1)); strncpy(tmp, string, (len + 1));
return tmp; return tmp;
} }
@ -86,30 +78,43 @@ ts_args* ts_get_arguments(const char *filename, const char *path)
syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_get_arguments)\n"); syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_get_arguments)\n");
exit(3); exit(3);
} }
char separator[2] = ";\0"; char separator[2] = ";\0";
char *part = NULL; char *part = NULL;
int len = strlen(filename); int len = strlen(filename);
int next = 1; /* reading the next iteration */
char *tmp_filename = (char*) calloc(1, sizeof(char) * (len + 1)); char *tmp_filename = (char*) calloc(1, sizeof(char) * (len + 1));
if (!tmp_filename) if (!tmp_filename)
{ {
syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_copy_string)\n"); syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_get_arguments)\n");
exit(3); exit(3);
} }
strncpy(tmp_filename, filename, (len + 1)); strncpy(tmp_filename, filename, (len + 1));
part = strtok(tmp_filename, separator); part = strtok(tmp_filename, separator);
while (part) while (part)
{ {
switch (args->size) switch (args->size)
{ {
case 0: case 0:
regex_t regex;
regcomp(&regex, "^01-[0-9a-f]{2}(-[0-9a-f]{2}){5}$", REG_EXTENDED);
int reti = regexec(&regex, part, 0, NULL, 0);
if (reti)
{
syslog(LOG_NOTICE, "TRQ The MAC address was entered incorrectly (ts_get_arguments)\n");
exit(100);
}
args->file_dst = ts_copy_string(part); args->file_dst = ts_copy_string(part);
args->path_dst = ts_concat_path(part); args->path_dst = ts_concat_path(part);
break; break;
case 1: case 1:
if (!strncmp("cr", part, 3)) {}
else if (!strncmp("rm", part, 3))
next = 0;
else
{
syslog(LOG_NOTICE, "TRQ The command was specified incorrectly (ts_get_arguments)\n");
exit(100);
}
args->command = ts_copy_string(part); args->command = ts_copy_string(part);
break; break;
case 2: case 2:
@ -117,19 +122,21 @@ ts_args* ts_get_arguments(const char *filename, const char *path)
args->path_src = ts_concat_path(part); args->path_src = ts_concat_path(part);
break; break;
default: default:
syslog(LOG_NOTICE, "TRQ Invalid request format (ts_get_arguments)\n");
exit(100);
} }
++args->size; ++args->size;
if (next)
part = strtok(NULL, separator); part = strtok(NULL, separator);
else
part = NULL;
} }
free(tmp_filename); free(tmp_filename);
if (!args->size) if (!args->size)
{ {
free(args); free(args);
args = NULL; args = NULL;
} }
return args; return args;
} }