# tr143-server
This repo contains files to setup TR-143 server. The server provides ping, download/upload via http/ftp and udp echo tests

# Run Server
To run the server execute **docker compose up -d** command inside the project root folder:

```shell
docker compose up -d
[+] Building 1.5s (19/19) FINISHED                                                                                                                                                           docker:default
 => [tr143-server internal] load build definition from Dockerfile                                                                                                                                      0.0s
 => => transferring dockerfile: 1.48kB                                                                                                                                                                 0.0s
 => [tr143-server internal] load .dockerignore                                                                                                                                                         0.0s
 => => transferring context: 2B                                                                                                                                                                        0.0s
 => [tr143-server internal] load metadata for docker.io/library/debian:12                                                                                                                              1.5s
 => [tr143-server  1/14] FROM docker.io/library/debian:12@sha256:bac353db4cc04bc672b14029964e686cd7bad56fe34b51f432c1a1304b9928da                                                                      0.0s
 => [tr143-server internal] load build context                                                                                                                                                         0.0s
 => => transferring context: 90B                                                                                                                                                                       0.0s
 => CACHED [tr143-server  2/14] RUN apt update && apt install -y --force-yes     sudo     tar     git     ccache     libsystemd-dev     autoconf     automake     libtool     libltdl-dev     pkg-con  0.0s
 => CACHED [tr143-server  3/14] RUN mkdir -p /var/www/tr143/download     /var/www/tr143/upload     /var/akcom-udpecho/build     /var/run/akcom-udpecho                                                 0.0s
 => CACHED [tr143-server  4/14] COPY tr143 /etc/nginx/sites-available/tr143                                                                                                                            0.0s
 => CACHED [tr143-server  5/14] COPY upload.php /var/www/tr143/upload                                                                                                                                  0.0s
 => CACHED [tr143-server  6/14] COPY entrypoint.sh /entrypoint.sh                                                                                                                                      0.0s
 => CACHED [tr143-server  7/14] RUN chmod +x /entrypoint.sh                                                                                                                                            0.0s
 => CACHED [tr143-server  8/14] WORKDIR /var/akcom-udpecho                                                                                                                                             0.0s
 => CACHED [tr143-server  9/14] RUN git clone https://github.com/alaskacommunications/akcom-udpecho.git build     && cd build     && ./autogen.sh     && ./configure     && make     && make install   0.0s
 => CACHED [tr143-server 10/14] RUN ln -s /etc/nginx/sites-available/tr143 /etc/nginx/sites-enabled/                                                                                                   0.0s
 => CACHED [tr143-server 11/14] RUN sed -i 's/upload_max_filesize = .*/upload_max_filesize = 300M/' /etc/php/8.2/fpm/php.ini &&     sed -i 's/post_max_size = .*/post_max_size = 300M/' /etc/php/8.2/  0.0s
 => CACHED [tr143-server 12/14] RUN dd if=/dev/zero of=/var/www/tr143/download/speed_test bs=1M count=300                                                                                              0.0s
 => CACHED [tr143-server 13/14] RUN chown -R www-data:www-data /var/www/tr143                                                                                                                          0.0s
 => CACHED [tr143-server 14/14] RUN chmod 644 /var/www/tr143/upload/upload.php                                                                                                                         0.0s
 => [tr143-server] exporting to image                                                                                                                                                                  0.0s
 => => exporting layers                                                                                                                                                                                0.0s
 => => writing image sha256:3aa781a8d0ab815ab8a62ee41196b4804f5866f2d198b0e67e2d1cd44126a752                                                                                                           0.0s
 => => naming to docker.io/library/tr143-server-tr143-server                                                                                                                                           0.0s
[+] Running 1/1
 ✔ Container tr143-server-tr143-server-1  Started
```

After that services will be available at the host IP address. You can check that by using **docker ps** command:

```shell
docker ps
CONTAINER ID   IMAGE                       COMMAND            CREATED         STATUS         PORTS     NAMES
88e4aea405c1   tr143-server-tr143-server   "/entrypoint.sh"   2 minutes ago   Up 2 minutes             tr143-server
```
Also you can exectute netstat commands to check if services ports are up:

**NGINX**
```shell
sudo netstat -lpont | grep "nginx"
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      7300/nginx: master   off (0.00/0/0)
tcp6       0      0 :::80                   :::*                    LISTEN      7300/nginx: master   off (0.00/0/0)
```

**UDP ECHO**
```shell
sudo netstat -lun | grep 3000
udp       0      0 0.0.0.0:30007                0.0.0.0:*
udp       0      0 0.0.0.0:30008                0.0.0.0:*
```

**FTP SERVER**
```shell
tcp        0      0 0.0.0.0:21              0.0.0.0:*               LISTEN      102464/vsftpd        off (0.00/0/0)
```

**How to access the container shell**

First check the container name or id. After that execute the bellow command to access the container shell.

```code
docker exec -it container_name_or_id bash
```

```shell
docker ps
CONTAINER ID   IMAGE                       COMMAND                  CREATED         STATUS         PORTS     NAMES
2b6d742172e6   tr143-server-tr143-server   "/usr/bin/supervisor…"   3 seconds ago   Up 2 seconds             tr143-server-tr143-server-1
 [~/Documents/GitHub/tr143-server]> docker exec -it tr143-server-tr143-server-1 bash
root@leonardo-OptiPlex-3050:/var/akcom-udpecho#
```

**Change Dockerfile settings**

If you need to change anything inside the Dockerfile don't forget to rebuild the image after saving the changes. To do that first remove all containers using the tr143-server image and after that remove the image as well:

```shell
docker ps
CONTAINER ID   IMAGE                       COMMAND                  CREATED         STATUS         PORTS     NAMES
2891b1d01003   tr143-server-tr143-server   "/usr/bin/supervisor…"   5 seconds ago   Up 4 seconds             tr143-server-tr143-server-1
┌[leonardo@leonardo-OptiPlex-3050] [/dev/pts/1] [main ⚡]
└[~/Documents/GitHub/tr143-server]> docker compose down
[+] Running 1/1
 ✔ Container tr143-server-tr143-server-1  Removed                                                                                                                                           1.4s
└[~/Documents/GitHub/tr143-server]> docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
└[~/Documents/GitHub/tr143-server]> docker rmi tr143-server-tr143-server
Untagged: tr143-server-tr143-server:latest
Deleted: sha256:15cab85aeedabcd12ea7797824b7b5fc08892cef904c9ec02849240c210c08b9
```

After these steps you can build the image with the new settings by running **docker compose up -d**


# FTP Server

FTP user and password must be set inside the dockerfile before building the image. The standard is:

FTPUser: ftptr143

Password: F3t4u3r@v3nk0

# UDP Echo Server and Client

Reference: https://github.com/alaskacommunications/akcom-udpecho

Utilities
=========

akcom-udpecho
-------------

_akcom-udpecho_ is a shell utility for testing UDP echo servers. _akcom-udpecho_
supports for RFC 862 compliant servers and TR-143 UDPEchoPlus compliant
servers.  If the UDP Echo variant is not specified, _akcom-udpecho_ will
attempt to determine the variant by examining the __TestRespSN__,
__TestRespRecvTimeStamp__, and __TestRespReplyTimeStamp__ fields of the
UDPEchoPlus packet for non-zero values.

_akcom-udpecho_ usage:

      Usage: akcom-udpecho [options] host [port]
      OPTIONS:
        -4                        connect via IPv4 only
        -6                        connect via IPv6 only
        -c count                  stop after sending count packets
        -d, --debug               print packet debugging information
        -e, --echoplus            expect echo plus response (default: auto detect)
        -h, --help                print this help and exit
        -i interval               interval between packet (default: 1 sec)
        -r, --rfc                 expect RFC compliant response (default: auto detect)
        -q, --quiet, --silent     do not print messages
        -s packetsize             size of data bytes to be sent. (default: 40 bytes)
        -t sec                    response timeout (default: 5 sec)
        -v, --verbose             enable verbose output
        -V, --version             print version number and exit

Example usage (RFC 862 compliant):

      $ akcom-udpecho -c 5 --rfc udpecho.example.com 30006
      UDPECHO udpecho.example.com:30006 (209.112.131.108:30006): 40 bytes
      udpecho_seq=1 time=17.3 ms
      udpecho_seq=2 time=13.7 ms
      udpecho_seq=3 time=19.0 ms
      udpecho_seq=4 time=18.3 ms
      udpecho_seq=5 time=12.6 ms

      --- udpecho.example.com udpecho statistics ---
      5 packets transmitted, 5 packets received, 0.0% packet loss
      round-trip min/avg/max = 12.6/16.1/19.0 ms
      $

Example usage (TR-143 UDPEchoPlus compliant) using server with 100000 us
random delay:

      $ akcom-udpecho -c 5 --echoplus udpecho.example.com 30006
      UDPECHO udpecho.example.com:30006 (209.112.131.108:30006): 40 bytes
      udpecho_seq=1 failures=0 time=158.0 ms delay=77.9 ms adj_time=80.1 ms
      udpecho_seq=2 failures=0 time=109.1 ms delay=29.2 ms adj_time=79.9 ms
      udpecho_seq=3 failures=0 time=136.1 ms delay=56.2 ms adj_time=79.9 ms
      udpecho_seq=4 failures=0 time=83.1 ms delay=3.0 ms adj_time=80.0 ms
      udpecho_seq=5 failures=0 time=133.2 ms delay=53.1 ms adj_time=80.0 ms

      --- udpecho.example.com udpecho statistics ---
      5 packets transmitted, 5 packets received, 0.0% packet loss
      round-trip min/avg/max = 83.1/123.9/158.0 ms
      adjusted round-trip min/avg/max = 79.9/80.0/80.1 ms
      $

akcom-udpechod
--------------

_akcom-udpechod_ is simple UDP echo server.  The __drop__ and __delay__
features should not be used concurrently by multiple clients. Currently
_akcom-udpechod_ processes each packet sequentially  which causes all packets
received before previous packets have been processed to be skewed when using
the __drop__ and __delay__ features.

_akcom-udpechod_ usage:

      Usage: akcom-udpechod [options]
      OPTIONS:
        -d num,  --drop=num       set packet drop probability [0-99] (default: 0%)
        -D usec, --delay=usec     set echo delay range to microseconds (default: 0 us)
        -e,      --echoplus       enable echo plus, not RFC compliant
        -f str,  --facility=str   set syslog facility (default: daemon)
        -g gid,  --group=gid      setgid to gid (default: none)
        -h,      --help           print this help and exit
        -l addr, --listen=addr    bind to IP address (default: all)
        -n,      --foreground     do not fork
        -p port, --port=port      list on port number (default: 30006)
        -P file, --pidfile=file   PID file (default: /var/run/akcom-udpechod.pid)
        -r,      --rfc            RFC compliant echo protocol (default)
        -u uid,  --user=uid       setuid to uid (default: none)
        -v,      --verbose        enable verbose output
        -V,      --version        print version number and exit

Example usage (RFC 862 compliant):

      akcom-udpechod \
         --port 30007 \
         --pidfile /var/run/akcom-udpecho/akcom-udpecho.pid \
         --user nobody \
         --group nobody \
         --delay=10000 \
         --drop=10 \
         --rfc

Example usage (TR-143 UDPEchoPlus compliant):

      akcom-udpechod \
         --port 30007 \
         --pidfile /var/run/akcom-udpecho/akcom-udpecho.pid \
         --echoplus \
         --user nobody \
         --group nobody \
         --delay=10000 \
         --drop=10 \
         --echoplus

# Web Server Configuration
HTTP dowload and upload tests are supported via NGINX web server. The configuration is inside the tr143 file.

## Download URL

The download URL is set as **http://server_ip_or_dns/download/speed_test**.

This URL points to the /var/www/tr143/download/speed_test directory inside the container.

By default docker image builts speed_test file with 300MB size. If you wish to increase or decrease this size just change the bellow section inside Dockerfile:

```docker
#Create download files
RUN dd if=/dev/zero of=/var/www/tr143/download/speed_test bs=1M count=300
```

## Upload URL

The upload URL is set as **http://server_ip_or_dns/upload/**.

This URL points to the /var/www/tr143/upload/ directory inside the container.

## Server Name and TCP port
Server name and TCP port directives are set in the beginning of the config file.

```
server {
    listen 80;
    server_name 10.147.20.74;
```

To listen to a different tcp port change the parameter **listen**. For example if you want the server to listen on tcp port 88:

```
server {
    listen 88;
```

Server name can be the IP address or a DNS that points to the host. However if you use a DNS and this domain name is not set in this file you will get a HTTP error 404 (HTTP NOT FOUD).
Let's say you wish to use the following DNS to access the web server: **tr143.venko.local**. In this case you should set server name as:

```
server {
    listen 80;
    server_name tr143.venko.local;
```

## Max Upload file size
The server will start with a default mas file size of 300MB for upload. If you want to change this follow the bellow steps:

**Nginx Config**

Change the parameter client_max_body_size inside the tr143 file. For example to allow an upload of 500MB:

```
location /upload/ {
        client_max_body_size 500M;
```

**PHP config**

PHP configs are being set using sed command inside the Dockerfile. If you wish to change file size also change bellow lines in this file:

```
# Adjust PHP configuration
RUN sed -i 's/upload_max_filesize = .*/upload_max_filesize = 500M/' /etc/php/8.2/fpm/php.ini && \
    sed -i 's/post_max_size = .*/post_max_size = 500M/' /etc/php/8.2/fpm/php.ini
```

# Test Scripts

Inside the test_scripts folder there are 4 scripts to test Diagnostics HTTP Download, HTTP Upload, ping and complete diagnostics. In order to use these scripts you must configure the config.ini file.

```ini
[config]
ACS_HOST=192.168.0.21
ACS_PORT=7557
DEVICE_ID=443B32-1200R-ITBS32B9F3BD
```
 - **ACS_HOST** - The IP address or dns for the TR069 server that the device under test is connected.
 - **ACS_PORT** - The tcp port wich the TR069 server API is listening.
 - **DEVICE_ID** - The device id that the CPE is using in the TR069 server.

 After configure this file you must also check for the tr069 parameters inside the test scripts. Usually each vendor has it own parameter tree. So you will need to change it accordingly. For example:

Mikrotik PING diagnostics tree:
 ```code
Device.IP.Diagnostics.IPPing
 ```

 Intelbras PING Diagnostics tree:
 ```code
 InternetGatewayDevice.IPPingDiagnostics
 ```

 **download.py**

 ```python
 import time
from tr069_request import AcsRequest

#Instancia a classe AcsRequest
acs = AcsRequest()

#Faz o refresh do objeto para forçar a cpe a atualizar
ret = acs.send_request({"name": "refreshObject", "objectName": "InternetGatewayDevice.DownloadDiagnostics.DiagnosticsState"})
if str(ret) == "200":
    print("Efetuado refresh do objeto")
else:
    print("Erro ao fazer o refresh do objeto: ", str(ret))

#Seta a URL de downlod do teste
parameter_values = ["InternetGatewayDevice.DownloadDiagnostics.DownloadURL","http://10.5.9.159/download/speed_test", "xsd:string"]
ret = acs.send_request({"name": "setParameterValues", "parameterValues": [parameter_values]})
if str(ret) == "200":
    print("URL de download alterada com sucesso.")
else:
    print("Erro ao alterar a URL de download:", str(ret))

time.sleep(5)

#Solicita o teste de download para a CPE
parameter_values = ["InternetGatewayDevice.DownloadDiagnostics.DiagnosticsState", "Requested", "xsd:string"]
ret = acs.send_request({"name": "setParameterValues", "parameterValues": [parameter_values]})
if str(ret) == "200":
    print("Download solicitado com sucesso")
else:
    print("Erro ao solicitar o download:", str(ret))
 ```
You need to check the parameter path (InternetGatewayDevice.DownloadDiagnostics.DownloadURL). Each vendor has a different path for the Diagnostics tests. So you should check the device correct path and set it in the script before executing it.

After all parameters are set you can execute the test:

```shell
python3 download.py
Efetuado refresh do objeto
URL de download alterada com sucesso.
Download solicitado com sucesso
```

## Diagnostics script

The diagnostics.py script performs http download/upload and icmp tests. Prints all tests results:

```shell
python3 diagnostics.py
Download completo.
Download Speed: 334.92 Mbps
Upload completo.
Upload Speed: 241.69 Mbps
Ping completo.
10 pacotes enviados, 10 recebidos, 0.00% de perda de pacotes.
rtt min/avg/max = 0.25/0.474/1.803 ms
```

# Upload handler

To keep fileystem always clean there is process wich will watch for new files in ftp and http upload directories. If the process finds a new file inside these folders it will delete them.

The shell script to delete files is **upload_handler.sh**

```shell
#!/bin/bash

DIRECTORY_1="/home/ftptr143"
DIRECTORY_2="/var/www/tr143/upload"

inotifywait -m -r -e create --format '%w%f' "$DIRECTORY_1" "$DIRECTORY_2" | while read NEW_FILE
do
    echo "New file detected: $NEW_FILE"
    rm "$NEW_FILE"
    echo "File deleted: $NEW_FILE"
done
```
If you change the ftp username it will also be necessary to change it's home directory here.