From 29da8777e6a6e08f90cada59ae301cfba4176a2e Mon Sep 17 00:00:00 2001 From: Alexander Zhirov Date: Fri, 25 Apr 2025 17:04:22 +0300 Subject: [PATCH] init --- APKBUILD | 52 ++++++++++++++ README.md | 141 ++++++++++++++++++++++++++++++++++++++ fix-common.patch | 24 +++++++ img/protocol.png | Bin 0 -> 9782 bytes in.tftpd.confd | 15 ++++ in.tftpd.initd | 21 ++++++ trq/trq.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++ trq/trq.h | 30 ++++++++ trq/trq.patch | 126 ++++++++++++++++++++++++++++++++++ 9 files changed, 582 insertions(+) create mode 100644 APKBUILD create mode 100644 README.md create mode 100644 fix-common.patch create mode 100644 img/protocol.png create mode 100644 in.tftpd.confd create mode 100644 in.tftpd.initd create mode 100644 trq/trq.c create mode 100644 trq/trq.h create mode 100644 trq/trq.patch diff --git a/APKBUILD b/APKBUILD new file mode 100644 index 0000000..6f71b50 --- /dev/null +++ b/APKBUILD @@ -0,0 +1,52 @@ +# Maintainer: Alexander Zhirov +pkgname=tftp-hpa-trq +pkgver=5.2 +pkgrel=1 +pkgdesc="Official tftp server with TRQ" +url="https://git.zhirov.kz/alexander/tftp-hpa-trq" +arch="all" +license="BSD" +subpackages="$pkgname-doc" +source="https://www.kernel.org/pub/software/network/tftp/tftp-hpa/tftp-hpa-$pkgver.tar.xz + in.tftpd.initd + in.tftpd.confd + fix-common.patch + trq/trq.patch + trq/trq.c + trq/trq.h + " + +options="!check" + +prepare() { + # После распаковки архива необходимо изменить имя директории на корректное + mv "$srcdir/tftp-hpa-$pkgver" "$srcdir/$pkgname-$pkgver" + default_prepare +} + +build() { + cp $srcdir/trq.c $builddir/tftpd + cp $srcdir/trq.h $builddir/tftpd + + ./configure \ + --build=$CBUILD \ + --host=$CHOST \ + --prefix=/usr \ + --mandir=/usr/share/man + make +} + +package() { + make INSTALLROOT="$pkgdir" install + install -d "$pkgdir"/var/tftpboot + install -Dm755 "$srcdir"/in.tftpd.initd "$pkgdir"/etc/init.d/in.tftpd-trq + install -Dm644 "$srcdir"/in.tftpd.confd "$pkgdir"/etc/conf.d/in.tftpd-trq +} + +sha512sums="a5198e923a6e58281f749dc77b3f3ed8579e56b6f0fd6a17482cc88bdc8d34b6702c7c709717885b9b937ecae459d9a832328a49a2e3536dc7432cdb39d2a394 tftp-hpa-5.2.tar.xz +0d103efc8a6febc94c599d984ba22e3272c422619b548a24953b006c99f2739ad8149543a09b06a50a2367e877117b1ee32f8c79bb81d19a43bccdc7ed1f13a6 in.tftpd.initd +b13d18d2918ece59df61a8239692b91f8b491659b57b63293ca2b99347f0503a213f1f7dd80165478811b11fb1d5537aea6e8fd3de907d880224205c5c65b0bf in.tftpd.confd +40127e7ce276a2bc015255dbeef2665bfe8ff006b1e1d8fb79797e946d6030fd74606cffe0bea11eaad276a693f223faaaf1c1ccb5f276b40fdad40b366172b7 fix-common.patch +fbbf2c15dd1f3fef96672fe0a4b7b424e7ad84ba4eb456c07498d33742662c5859b800c8cdf61c36c5927c00500f560a4f1d48aefaa5d5f5ccbb622538e9140e trq.patch +314eea07339e7c8605a69db65638aacfb488077f39b127bdc81369202d0edae6545a456705cebe08fde3729293b7609892a09d91ec2f7dc93b63d693b10ff833 trq.c +29cc72f3197bcaea4a88dace5c91d53dad5d20a397752198e601e2ed83fdb66fca50a5b4b03c4d3033ebd7a0be1e90801a692c514733412d8d96cafde26e0837 trq.h" diff --git a/README.md b/README.md new file mode 100644 index 0000000..3ab14b9 --- /dev/null +++ b/README.md @@ -0,0 +1,141 @@ +# tftp-hpa-trq + +- [Описание](#описание) +- [Пример запроса на `php`](#пример-запроса-на-php) +- [Пример запроса на `python`](#пример-запроса-на-python) +- [Сборка пакета в 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-;; +``` +где +- `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); +``` + +## Пример запроса на Python + +Создание пакета на Python для создания символической ссылки, отправляемого на TFTP-сервер: + +```python +import socket + +opcode = 6 # TRQ opcode +request = '01-ff-ff-ff-ff-ff-ff;cr;thinstation' +mode = 'octet' +ip = '192.168.0.11' +port = 69 + +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +package = chr(0) + chr(opcode) + request + chr(0) + mode + chr(0) +sock.sendto(package.encode(), (ip, port)) +sock.close() +``` + +## Сборка пакета в Docker + +Склонировать репозиторий в удобное место: + +```sh +git clone https://git.zhirov.kz/alexander/tftp-hpa-trq.git +``` + +Войти в оболочку `alpine` для сборки пакета запустив `docker` командой: + +```sh +docker run --rm -it -v $PWD/tftp-hpa-trq:/home/packager/reposerve/main/tftp-hpa-trq alpine:latest /bin/ash +``` + +Установить инструменты разработчика: + +```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 +cd /home/packager/reposerve/main/tftp-hpa-trq +REPODEST=~/packages/latest abuild -r +``` + +Для установки в других экземплярах `alpine` возможно понадобятся сгенерированные ранее ключи для сборки пакета (`/home/packager/.abuild/{*.rsa,*.rsa.pub}`). + +### Генерация ключей + +Сгенерировать ключи: + +```sh +abuild-keygen -a -i +``` + +Или же прокинуть в контейнер свои ключи в `/home/packager/.abuild`. + + +## Безопасность + +Отсутствует проверка на источник запроса, так как сформировать запрос на создание/удаление символической ссылки выполняется в произвольной форме. diff --git a/fix-common.patch b/fix-common.patch new file mode 100644 index 0000000..1f082e8 --- /dev/null +++ b/fix-common.patch @@ -0,0 +1,24 @@ +diff -urN tftp-hpa-5.2.orig/tftp/main.c tftp-hpa-5.2/tftp/main.c +--- tftp-hpa-5.2.orig/tftp/main.c 2020-11-14 22:21:15.851650899 -0700 ++++ tftp-hpa-5.2/tftp/main.c 2020-11-14 22:21:41.878327755 -0700 +@@ -95,7 +95,7 @@ + int margc; + char *margv[20]; + const char *prompt = "tftp> "; +-sigjmp_buf toplevel; ++static sigjmp_buf toplevel; + void intr(int); + struct servent *sp; + int portrange = 0; +diff -urN tftp-hpa-5.2.orig/tftp/tftp.c tftp-hpa-5.2/tftp/tftp.c +--- tftp-hpa-5.2.orig/tftp/tftp.c 2020-11-14 22:21:15.851650899 -0700 ++++ tftp-hpa-5.2/tftp/tftp.c 2020-11-14 22:21:51.304998113 -0700 +@@ -48,7 +48,7 @@ + #define PKTSIZE SEGSIZE+4 + char ackbuf[PKTSIZE]; + int timeout; +-sigjmp_buf toplevel; ++static sigjmp_buf toplevel; + sigjmp_buf timeoutbuf; + + static void nak(int, const char *); diff --git a/img/protocol.png b/img/protocol.png new file mode 100644 index 0000000000000000000000000000000000000000..403d091c6466a3c166416195844ceff90b3002c7 GIT binary patch literal 9782 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

C567iFIw(*<#H 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 +#include +#include +#include +#include +#include + +void ts_free(ts_args *args) +{ + if (args) + { + if (args->command) + free(args->command); + if (args->file_src) + free(args->file_src); + if (args->file_dst) + free(args->file_dst); + if (args->path_src) + free(args->path_src); + if (args->command) + free(args->path_dst); + free(args); + } +} + +static char* ts_concat_path(const char *file) +{ + if (!file) + { + syslog(LOG_NOTICE, "TRQ Invalid value file (ts_concat_path)\n"); + exit(3); + } + const char *path_mac = "mac.cfg/"; + size_t len1 = strlen(path_mac); + size_t len2 = strlen(file); + char *result = (char*) malloc(sizeof(char) * (len1 + len2 + 1)); + if (!result) + { + syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_concat_path)\n"); + exit(3); + } + strncpy(result, path_mac, (len1 + 1)); + strncpy(result + len1, file, (len2 + 1)); + return result; +} + +static char* ts_copy_string(const char *string) +{ + if (!string) + return NULL; + int len = strlen(string); + char *tmp = (char*) calloc(1, sizeof(char) * (len + 1)); + if (!tmp) + { + syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_copy_string)\n"); + exit(3); + } + strncpy(tmp, string, (len + 1)); + return tmp; +} + +ts_args* ts_get_arguments(const char *filename, const char *path) +{ + ts_args *args = (ts_args*) calloc(1, sizeof(ts_args)); + if (!args) + { + syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_get_arguments)\n"); + exit(3); + } + char separator[2] = ";\0"; + char *part = NULL; + int len = strlen(filename); + int next = 1; /* reading the next iteration */ + char *tmp_filename = (char*) calloc(1, sizeof(char) * (len + 1)); + if (!tmp_filename) + { + syslog(LOG_NOTICE, "TRQ Disk full or allocation exceeded (ts_get_arguments)\n"); + exit(3); + } + strncpy(tmp_filename, filename, (len + 1)); + part = strtok(tmp_filename, separator); + while (part) + { + switch (args->size) + { + case 0: + regex_t regex; + regcomp(®ex, "^01-[0-9a-f]{2}(-[0-9a-f]{2}){5}$", REG_EXTENDED); + int reti = regexec(®ex, 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->path_dst = ts_concat_path(part); + break; + 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); + break; + case 2: + args->file_src = ts_copy_string(part); + args->path_src = ts_concat_path(part); + break; + default: + syslog(LOG_NOTICE, "TRQ Invalid request format (ts_get_arguments)\n"); + exit(100); + } + ++args->size; + if (next) + part = strtok(NULL, separator); + else + part = NULL; + } + free(tmp_filename); + if (!args->size) + { + free(args); + args = NULL; + } + return args; +} + +void ts_syslog(const ts_args *args) +{ + if (args) + { + if (args->size > 2) + syslog(LOG_NOTICE, "TRQ Create symlink %s on %s\n", args->file_dst, args->file_src); + else + syslog(LOG_NOTICE, "TRQ Remove symlink %s\n", args->file_dst); + } +} + +void ts_symlink(const ts_args *args) +{ + if (args) + { + if (args->size > 2) + { + if (access(args->path_src, F_OK) == 0 && !symlink(args->file_src, args->path_dst)) + syslog(LOG_NOTICE, "TRQ A symbolic link %s has been created\n", args->file_dst); + else + syslog(LOG_NOTICE, "TRQ Failed to create symbolic link %s. %s\n", args->file_dst, strerror(errno)); + } + else + { + if (access(args->path_dst, F_OK) == 0 && !unlink(args->path_dst)) + syslog(LOG_NOTICE, "TRQ A symbolic link %s has been removed\n", args->file_dst); + else + syslog(LOG_NOTICE, "TRQ Failed to remove symbolic link %s. %s\n", args->file_dst, strerror(errno)); + } + } +} diff --git a/trq/trq.h b/trq/trq.h new file mode 100644 index 0000000..d6828c3 --- /dev/null +++ b/trq/trq.h @@ -0,0 +1,30 @@ +/* + * trq.h + * + * Created on: 17 авг. 2022 г. + * Author: Alexander Zhirov + * Mail: alexander@zhirov.website + * Telegram: alexanderzhirov + */ + +#ifndef TRQ_H_ +#define TRQ_H_ + +#define TRQ 06 /* Thinstation */ + +typedef struct +{ + int size; + char *command; + char *file_src; + char *file_dst; + char *path_src; + char *path_dst; +} ts_args; + +ts_args* ts_get_arguments(const char*, const char*); +void ts_free(ts_args*); +void ts_syslog(const ts_args*); +void ts_symlink(const ts_args*); + +#endif diff --git a/trq/trq.patch b/trq/trq.patch new file mode 100644 index 0000000..7b64555 --- /dev/null +++ b/trq/trq.patch @@ -0,0 +1,126 @@ +diff --git a/Makefile b/Makefile +index 9ff12d8..3d5c537 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # You can do "make SUB=blah" to make only a few, or edit here, or both + # You can also run make directly in the subdirs you want. + +-SUB = lib common tftp tftpd ++SUB = lib common tftpd + + %.build: MCONFIG aconfig.h version.h + $(MAKE) -C $(patsubst %.build, %, $@) +@@ -17,7 +17,7 @@ SUB = lib common tftp tftpd + + all: MCONFIG $(patsubst %, %.build, $(SUB)) + +-tftp.build: lib.build common.build ++#tftp.build: lib.build common.build + tftpd.build: lib.build common.build + + install: MCONFIG $(patsubst %, %.install, $(SUB)) +@@ -68,7 +68,7 @@ configure: configure.in aclocal.m4 + autoconf + + version.h: version +- echo \#define VERSION \"tftp-hpa `cat version`\" > version.h ++ echo \#define VERSION \"tftp-hpa-trq `cat version`\" > version.h + + tftp.spec: tftp.spec.in version + sed -e "s/@@VERSION@@/`cat version`/g" < $< > $@ || rm -f $@ +diff --git a/tftpd/Makefile b/tftpd/Makefile +index a05335d..8e80113 100644 +--- a/tftpd/Makefile ++++ b/tftpd/Makefile +@@ -4,7 +4,7 @@ VERSION = $(shell cat ../version) + -include ../MCONFIG + include ../MRULES + +-OBJS = tftpd.$(O) recvfrom.$(O) misc.$(O) $(TFTPDOBJS) ++OBJS = tftpd.$(O) trq.$(O) recvfrom.$(O) misc.$(O) $(TFTPDOBJS) + + all: tftpd$(X) tftpd.8 + +@@ -18,9 +18,9 @@ tftpd.8: tftpd.8.in ../version + + install: all + mkdir -p $(INSTALLROOT)$(SBINDIR) $(INSTALLROOT)$(MANDIR)/man8 +- $(INSTALL_PROGRAM) tftpd$(X) $(INSTALLROOT)$(SBINDIR)/in.tftpd +- $(INSTALL_DATA) tftpd.8 $(INSTALLROOT)$(MANDIR)/man8/in.tftpd.8 +- cd $(INSTALLROOT)$(MANDIR)/man8 && $(LN_S) -f in.tftpd.8 tftpd.8 ++ $(INSTALL_PROGRAM) tftpd$(X) $(INSTALLROOT)$(SBINDIR)/in.tftpd-trq ++ $(INSTALL_DATA) tftpd.8 $(INSTALLROOT)$(MANDIR)/man8/in.tftpd-trq.8 ++ cd $(INSTALLROOT)$(MANDIR)/man8 && $(LN_S) -f in.tftpd-trq.8 tftpd-trq.8 + + clean: + rm -f *.o *.obj *.exe tftpd tftpsubs.c tftpsubs.h tftpd.8 +diff --git a/tftpd/tftpd.c b/tftpd/tftpd.c +index 1873e70..c3df336 100644 +--- a/tftpd/tftpd.c ++++ b/tftpd/tftpd.c +@@ -52,6 +52,7 @@ + #include "common/tftpsubs.h" + #include "recvfrom.h" + #include "remap.h" ++#include "trq.h" + + #ifdef HAVE_SYS_FILIO_H + #include /* Necessary for FIONBIO on Solaris */ +@@ -1038,7 +1039,7 @@ int main(int argc, char **argv) + + tp = (struct tftphdr *)buf; + tp_opcode = ntohs(tp->th_opcode); +- if (tp_opcode == RRQ || tp_opcode == WRQ) ++ if (tp_opcode == RRQ || tp_opcode == WRQ || tp_opcode == TRQ) + tftp(tp, n); + exit(0); + } +@@ -1077,6 +1078,7 @@ int tftp(struct tftphdr *tp, int size) + char *filename, *mode = NULL; + const char *errmsgptr; + u_short tp_opcode = ntohs(tp->th_opcode); ++ ts_args *args = NULL; + + char *val = NULL, *opt = NULL; + char *ap = ackbuf + 2; +@@ -1118,6 +1120,10 @@ int tftp(struct tftphdr *tp, int size) + nak(EACCESS, errmsgptr); /* File denied by mapping rule */ + exit(0); + } ++ if (tp_opcode == TRQ) /* Thinstation request */ ++ { ++ args = ts_get_arguments(filename, dirs[ndirs - 1]); ++ } + if (verbosity >= 1) { + tmp_p = (char *)inet_ntop(from.sa.sa_family, SOCKADDR_P(&from), + tmpbuf, INET6_ADDRSTRLEN); +@@ -1127,9 +1133,12 @@ int tftp(struct tftphdr *tp, int size) + } + if (filename == origfilename + || !strcmp(filename, origfilename)) +- syslog(LOG_NOTICE, "%s from %s filename %s\n", +- tp_opcode == WRQ ? "WRQ" : "RRQ", +- tmp_p, filename); ++ if (tp_opcode == TRQ) /* Thinstation request */ ++ ts_syslog(args); ++ else ++ syslog(LOG_NOTICE, "%s from %s filename %s\n", ++ tp_opcode == WRQ ? "WRQ" : "RRQ", ++ tmp_p, filename); + else + syslog(LOG_NOTICE, + "%s from %s filename %s remapped to %s\n", +@@ -1137,6 +1146,12 @@ int tftp(struct tftphdr *tp, int size) + tmp_p, origfilename, + filename); + } ++ if (tp_opcode == TRQ) ++ { ++ ts_symlink(args); ++ ts_free(args); ++ exit(0); ++ } + ecode = + (*pf->f_validate) (filename, tp_opcode, pf, &errmsgptr); + if (ecode) {