Finish server + client implementation (and fix bugs)

Co-authored-by: Ezequiel Bellver <ebellver@itba.edu.ar>
Co-authored-by: Juan Barmasch <jbarmasch@itba.edu.ar>
This commit is contained in:
Santiago Lo Coco 2022-06-20 20:55:57 -03:00
parent 9cac4bf50d
commit b503ad1204
24 changed files with 1226 additions and 1227 deletions

View File

@ -1,12 +1,8 @@
CCFLAGS = -std=c11 -Wall -Wextra -Wno-unused-parameter -Wno-implicit-fallthrough -pedantic -pedantic-errors -fsanitize=address -fno-omit-frame-pointer -g -D_POSIX_C_SOURCE=200809L CCFLAGS = -std=c11 -Wall -Wextra -Wno-unused-parameter -Wno-implicit-fallthrough -pedantic -pedantic-errors -fsanitize=address -fno-omit-frame-pointer -g -D_POSIX_C_SOURCE=200809L
# CCFLAGS = -std=c11 -Wall -Wextra -Wno-unused-parameter -Wno-implicit-fallthrough -pedantic -pedantic-errors -fsanitize=address -fno-omit-frame-pointer -g -D_POSIX_C_SOURCE=200112L LDFLAGS = -lpthread
LDFLAGS = -lpthread -lm
SERVER_SOURCES=src/args.c src/selector.c src/socks5nio.c src/confignio.c src/stm.c src/hello.c src/request.c src/netutils.c src/buffer.c src/server.c src/auth.c src/cmd.c src/parser.c src/parser_utils.c SERVER_SOURCES=src/args.c src/selector.c src/socks5nio.c src/confignio.c src/stm.c src/hello.c src/request.c src/netutils.c src/buffer.c src/server.c src/auth.c src/cmd.c src/parser.c src/parser_utils.c
CLIENT_SOURCES=src/client.c CLIENT_SOURCES=src/client.c src/netutils.c
SERVER_LIBS=include/args.h include/selector.h include/socks5nio.h include/stm.h include/hello.h include/request.h include/buffer.h include/server.h
CLIENT_LIBS=
SERVER_OBJECTS=$(SERVER_SOURCES:.c=.o) SERVER_OBJECTS=$(SERVER_SOURCES:.c=.o)
CLIENT_OBJECTS=$(CLIENT_SOURCES:.c=.o) CLIENT_OBJECTS=$(CLIENT_SOURCES:.c=.o)
SERVER_TARGET=socks5d SERVER_TARGET=socks5d
@ -15,7 +11,7 @@ CLIENT_TARGET=client
all: $(SERVER_OBJECTS) $(SERVER_TARGET) $(CLIENT_OBJECTS) $(CLIENT_TARGET) all: $(SERVER_OBJECTS) $(SERVER_TARGET) $(CLIENT_OBJECTS) $(CLIENT_TARGET)
%.o : %.c %.o : %.c
$(CC) $(CCFLAGS) $(LDFLAGS) -I ./include -c $< -o $@ $(CC) $(CCFLAGS) -I ./include -c $< -o $@
$(SERVER_TARGET): $(SERVER_OBJECTS) $(SERVER_TARGET): $(SERVER_OBJECTS)
$(CC) $(CCFLAGS) $(LDFLAGS) -I ./include -o $@ $^ $(CC) $(CCFLAGS) $(LDFLAGS) -I ./include -o $@ $^

View File

@ -23,16 +23,52 @@ make all
## Ejecución <a name="ejecución"></a> ## Ejecución <a name="ejecución"></a>
Ahora, tendrá dos ejecutables: `client` y `server`. Note que primero debe correr el `server` y luego conectarse con el `client`. Ahora, tendrá dos ejecutables: `client` y `socks5d`.
El servidor por defecto utilizará un _TOKEN_ que debe ser una `env` variable. Por ejemplo, puede configurar una mediante:
```bash ```bash
./server export BPROXY_TOKEN=0x0FF1CEDEADB00B1E
```
Si no se encuentra una token al momento de ejecutar el `server` el mismo terminará con error.
Ahora, puede correr el `server` y luego, si desea hacer alguna configuración, conectarse con el `client`.
```bash
./socks5d ${PARAMS}
``` ```
y en otra terminal y en otra terminal
```bash ```bash
./client ./client ${PARAMS}
```
## Casos de uso <a name="casos-de-uso"></a>
Se mostrarán dos casos típicos de uso del servidor.
Aquí se tiene al servidor proxy corriendo en 127.0.0.1:1080 y se utiliza a este para conectarse a 192.168.10.120:110 (una PC en la misma subred corriendo un servidor POP3 local). Además, se está autenticando con el usuario `user:pass`.
```bash
./socks5d -u user:pass
ncat -C -v --proxy 127.0.0.1:1080 --proxy-type socks5 192.168.10.120 110 --proxy-auth user:pass
```
Por otro lado, aquí se usó `curl` para acceder a http://api.ipify.org mediante el proxy (también corriendo en la misma IP que el ejemplo anterior).
```bash
./socks5d -u user:pass
curl -x socks5://user:pass@127.0.0.1:1080 http://api.ipify.org
```
En este caso se quiere obtener la cantidad de páginas de usuarios que hay en el servidor proxy, mediante -L se especifica la direccion IP del servidor de configuración (por defecto 127.0.0.1), con -P se especifica el puerto (por defecto 8080).
Una vez que se obtiene la cantidad de páginas se le pide el listado de usuarios pertenecientes a la 2da página, en caso de que el servidor no cuente con usuarios suficientes para tener 2 páginas, imprimirá un error especificando que el valor pasado no es válido. En cambio, si se cuentan con usuarios suficientes se listarán separados por un '\n'
```bash
./client 1148926835748244254 -L 192.168.10.119 -P 8100 -f
./client 1148926835748244254 -L 192.168.10.119 -P 8100 -u 2
``` ```
## Testeos <a name="tests"></a> ## Testeos <a name="tests"></a>
@ -46,29 +82,18 @@ make test
Por último, si quiere hacer un análisis dinámico (usando [valgrind](https://valgrind.org/)) puede hacerlo mediante: Por último, si quiere hacer un análisis dinámico (usando [valgrind](https://valgrind.org/)) puede hacerlo mediante:
```bash ```bash
valgrind ./server valgrind ./socks5d
```
y en otra terminal
```bash
valgrind ./client
``` ```
## Limpieza <a name="limpieza"></a> ## Limpieza <a name="limpieza"></a>
Si desea borrar los archivos creados luego de la compilación debe correr: Si desea borrar los archivos creados luego de la compilación (y los testeos si se hubiesen corrido) debe correr:
```bash ```bash
make clean make clean
``` ```
Note que si, además, quiere borrar el output de los tests (de `PVS-Studio` específicamente), lo puede hacer con:
```bash
make cleanTest
```
# Autores # Autores
- Barmasch, Juan Martín (61033) ### Bottler:
- Bellver, Ezequiel (61268) - Barmasch, Juan Martín (61033)
- Lo Coco, Santiago (61301) - Bellver, Ezequiel (61268)
- Lo Coco, Santiago (61301)

View File

@ -1,4 +1,4 @@
Bottler Protocol version 1 Bottler Configuration Protocol version 1
1. Introduction 1. Introduction
@ -9,13 +9,12 @@ Note:
Unless otherwise noted, the decimal numbers appearing in packet - Unless otherwise noted, the decimal numbers appearing in packet -
format diagrams represent the length of the corresponding field, in format diagrams represent the length of the corresponding field, in
octets. Where a given octet must take on a specific value, the octets. Where a given octet must take on a specific value, the
syntax X'hh' is used to denote the value of the single octet in that syntax X'hh' is used to denote the value of the single octet in that
field. When the word 'Variable' is used, it indicates that the field. When the size of a field is a range, it indicates that the
corresponding field has a variable length defined either by an corresponding field has a variable length defined either by an
associated (one or two octet) length field, or by a data type field. associated (one or two octet) length field.
Fields taking more than one octet are in network octet order.
NETWORK ORDER!!!
2. Requests 2. Requests
@ -29,45 +28,33 @@ Note:
The VER field is set to X'01' for this version of the protocol. The The VER field is set to X'01' for this version of the protocol. The
TOKEN field contains 8 bytes that authenticates the request. The TOKEN field contains 8 bytes that authenticates the request. The
CMD field describes the command that will be run. The CMD field describes the command that will be run. The PARAMETERS
PARAMETERS field describes the parameters that will be passed field describes the parameters that will be passed depending on the
depending on the CMD field value. CMD field value.
The values currently defined for CMD are: The values currently defined for CMD are:
o X'00' GET METRICS o X'00' GET METRICS
o X'01' GET BUFFER SIZE o X'01' GET USER PAGES
o X'02' SET BUFFER SIZE o X'02' LIST USERS
o X'03' GET TIMEOUT VALUE o X'03' MODIFY USERNAME
o X'04' SET TIMEOUT VALUE o X'04' MODIFY PASSWORD
o X'05' GET USER PAGES o X'05' ADD USER
o X'06' LIST USERS o X'06' DELETE USER
o X'07' GET USER LAST CONNECTION o X'07' GET PASSWORD DISSECTOR STATUS
o X'08' MODIFY USERNAME o X'08' SET PASSWORD DISSECTOR
o X'09' MODIFY PASSWORD o X'09' GET PROXY AUTHENTICATION STATUS
o X'0A' ADD USER o X'0A' SET PROXY AUTHENTICATION
o X'0B' DELETE USER
o X'0C' GET PASSWORD DISSECTOR STATUS
o X'0D' ENABLE/DISABLE PASSWORD DISSECTOR
o X'0E' GET PROXY AUTHENTICATION STATUS
o X'0F' ENABLE/DISABLE PROXY AUTHENTICATION
o X'10' GET PROXY SERVER STATUS
o X'11' START/STOP PROXY SERVER
o X'12' RESET PROXY SERVER
TODO: metodo para saber cuanto tiene una página? o lo hardcodeamos en el proto?
TODO: unknown command 0xFE 3. Commands
TODO: get users de ettercap (not quite)
2. Commands 3.1. CMD: X'00' - GET METRICS
CMD: X'00' - GET METRICS Requests historical metrics values. Which are historical
connections, current connections and total bytes transmitted.
Requests historical metrics values. Which are hostorical Connections are represented as an unsigned int taking 4 bytes
connections, current connections and total bytes transmited. Total bytes transmitted as an unsigned long taking 8 bytes.
Connections are represented as an unisgned int taking 4 bytes
Total bytes transmited as a unsigned long taking 8 bytes.
Request: Request:
+-------+-------+---------+ +-------+-------+---------+
@ -86,137 +73,23 @@ CMD: X'00' - GET METRICS
The possible values for CODE are: The possible values for CODE are:
o X'00' OK o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN o X'B0' INVALID TOKEN
o X'D0' VERSION NOT SUPPORTED o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED o X'FF' METHOD NOT SUPPORTED
CMD: X'01' - GET BUFFER SIZE 3.2. CMD: X'01' - GET USER PAGES
Requests buffer size used for the proxy SOCKS server.
Response comes with a response code and one integer
representing the buffer size taking 2 bytes.
Request:
+-------+-------+---------+
| VER | TOKEN | CMD |
+-------+-------+---------+
| X'01' | 8 | X'01' |
+-------+-------+---------+
Response:
+-------+--------+-----------+
| VER | CODE | BUFF SIZE |
+-------+--------+-----------+
| X'01' | 1 | 2 |
+-------+--------+-----------+
The possible values for CODE are:
o X'00' OK
o X'B0' INVALID TOKEN
o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED
CMD: X'02' - SET BUFFER SIZE
TODO: decidir bien los tamaños
Requests the modification of the buffer size used for the
proxy SOCKS server. Value must be between 256 and 16.384
Response comes with a response code indicating the output
of the action required
Request:
+-------+-------+---------+-----------+
| VER | TOKEN | CMD | BUFF SIZE |
+-------+-------+---------+-----------+
| X'01' | 8 | X'02' | 2 |
+-------+-------+---------+-----------+
Response:
+-------+--------+
| VER | CODE |
+-------+--------+
| X'01' | 1 |
+-------+--------+
The possible values for CODE are:
o X'00' OK
o X'B0' INVALID TOKEN
o X'C0' INVALID PARAMETER VALUE
o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED
CMD: X'03' - GET TIMEOUT VALUE
Requests the timeout value used in the proxy SOCKS server.
Response comes with a response code and one integer
representing the timeout value taking 2 bytes.
Request:
+-------+-------+---------+
| VER | TOKEN | CMD |
+-------+-------+---------+
| X'01' | 8 | X'03' |
+-------+-------+---------+
Response:
+-------+--------+---------+
| VER | CODE | TIMEOUT |
+-------+--------+---------+
| X'01' | 1 | 2 |
+-------+--------+---------+
The possible values for CODE are:
o X'00' OK
o X'B0' INVALID TOKEN
o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED
CMD: X'04' - SET TIMEOUT VALUE
TODO: decidir bien los valores
Requests the modification of the timeout value used in the
proxy SOCKS server. Value must be between 128 and 2048
Response comes with a response code indicating the output
of the action required
Request:
+-------+-------+---------+---------+
| VER | TOKEN | CMD | TIMEOUT |
+-------+-------+---------+---------+
| X'01' | 8 | X'04' | 2 |
+-------+-------+---------+---------+
Response:
+-------+--------+
| VER | CODE |
+-------+--------+
| X'01' | 1 |
+-------+--------+
The possible values for CODE are:
o X'00' OK
o X'B0' INVALID TOKEN
o X'C0' INVALID PARAMETER VALUE
o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED
CMD: X'05' - GET USER PAGES
Requests amount of pages of valid users for the proxy SOCKS Requests amount of pages of valid users for the proxy SOCKS
server. server.
Response comes as an integers taking 2 bytes. (representing) Response comes as an unsigned integer taking 2 bytes representing
amount of pages available containing the usernames of all valid users.
Request: Request:
+-------+-------+---------+ +-------+-------+---------+
| VER | TOKEN | CMD | | VER | TOKEN | CMD |
+-------+-------+---------+ +-------+-------+---------+
| X'01' | 8 | X'05' | | X'01' | 8 | X'01' |
+-------+-------+---------+ +-------+-------+---------+
Response: Response:
@ -229,49 +102,59 @@ CMD: X'05' - GET USER PAGES
The possible values for CODE are: The possible values for CODE are:
o X'00' OK o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN o X'B0' INVALID TOKEN
o X'D0' VERSION NOT SUPPORTED o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED o X'FF' METHOD NOT SUPPORTED
CMD: X'06' - LIST USERS 3.3. CMD: X'02' - LIST USERS
Requests amount of pages of valid users for the proxy SOCKS Requests an user page containing usernames of valid users for
server. the proxy SOCKS server for a given page number.
Response comes as an integers taking 2 bytes. (representing) Response comes as ascii values representing each username
separated by a '\n'. Maximum 5 users per response.
If there are less than 5 then the last username will have
"\n\n" at the end.
Request: Request:
+-------+-------+---------+--------+ +-------+-------+---------+--------+
| VER | TOKEN | CMD | PAGE | | VER | TOKEN | CMD | PAGE |
+-------+-------+---------+--------+ +-------+-------+---------+--------+
| X'01' | 8 | X'06' | 2 | | X'01' | 8 | X'02' | 2 |
+-------+-------+---------+--------+ +-------+-------+---------+--------+
Response: Response:
+-------+--------+---------------+ +-------+--------+---------------+
| VER | CODE | PAGE | | VER | CODE | PAGE SIZE |
+-------+--------+---------------+ +-------+--------+---------------+
| X'01' | 1 | Page size | | X'01' | 1 | Page size |
+-------+--------+---------------+ +-------+--------+---------------+
PAGE represents a page number greater or equal to 1.
The possible values for CODE are: The possible values for CODE are:
o X'00' OK o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN o X'B0' INVALID TOKEN
o X'C0' INVALID PARAMETER VALUE o X'C0' INVALID PARAMETER VALUE
o X'D0' VERSION NOT SUPPORTED o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED o X'FF' METHOD NOT SUPPORTED
CMD: X'08' - MODIFY USERNAME The INVALID PARAMETER VALUE code will be returned when
PAGE value is not a valid page.
3.4. CMD: X'03' - MODIFY USERNAME
Modifies username of user of proxy server. Modifies username of user of proxy server.
Response comes as with a code representing the output of Response comes with a code representing the output of
the action. the action.
Request: Request:
+-------+-------+---------+--------+-----------+---------+----------+ +-------+-------+---------+--------+-----------+---------+----------+
| VER | TOKEN | CMD | ULEN | UNAME | NULEN | NUNAME | | VER | TOKEN | CMD | ULEN | UNAME | NULEN | NUNAME |
+-------+-------+---------+--------+-----------+---------+----------+ +-------+-------+---------+--------+-----------+---------+----------+
| X'01' | 8 | X'08' | 1 | 1 to 255 | 1 | 1 to 255 | | X'01' | 8 | X'03' | 1 | 1 to 255 | 1 | 1 to 255 |
+-------+-------+---------+--------+-----------+---------+----------+ +-------+-------+---------+--------+-----------+---------+----------+
Response: Response:
@ -282,31 +165,39 @@ CMD: X'08' - MODIFY USERNAME
+-------+--------+ +-------+--------+
UNAME and NUNAME are valid SOCKSv5 usernames. NUNAME UNAME and NUNAME are valid SOCKSv5 usernames. NUNAME
represents de new value for the username of the user represents the new value for the username of the user
with the username UNAME. ULEN describes the length of with the username UNAME. ULEN describes the length of
UNAME, NULEN describes the length of NUNAME. UNAME, NULEN describes the length of NUNAME.
Both UNAME and NUNAME must only contain printable ASCII
characters other than ':'.
The possible values for CODE are: The possible values for CODE are:
o X'00' OK o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN o X'B0' INVALID TOKEN
o X'C0' INVALID PARAMETER VALUE o X'C0' INVALID PARAMETER VALUE
o X'C1' USER NOT FOUND o X'C1' USER NOT FOUND
o X'C1' USER ALREADY EXISTS
o X'D0' VERSION NOT SUPPORTED o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED o X'FF' METHOD NOT SUPPORTED
CMD: X'09' - MODIFY PASSWORD The INVALID PARAMETER VALUE code will be returned when
ULEN or NULEN is 0 or when there are invalid characters
in either UNAME or NUNAME.
3.5. CMD: X'04' - MODIFY PASSWORD
Modifies password of user of proxy server with username Modifies password of user of proxy server with username
UNAME. UNAME.
Response comes as with a code representing the output of Response comes with a code representing the output of
the action. the action.
Request: Request:
+-------+-------+---------+--------+-----------+-------+----------+ +-------+-------+---------+--------+-----------+-------+----------+
| VER | TOKEN | CMD | ULEN | UNAME | PLEN | PASS | | VER | TOKEN | CMD | ULEN | UNAME | PLEN | PASS |
+-------+-------+---------+--------+-----------+-------+----------+ +-------+-------+---------+--------+-----------+-------+----------+
| X'01' | 8 | X'09' | 1 | 1 to 255 | 1 | 1 to 255 | | X'01' | 8 | X'04' | 1 | 1 to 255 | 1 | 1 to 255 |
+-------+-------+---------+--------+-----------+-------+----------+ +-------+-------+---------+--------+-----------+-------+----------+
Response: Response:
@ -318,30 +209,37 @@ CMD: X'09' - MODIFY PASSWORD
UNAME is a valid SOCKSv5 username and PASS is a valid UNAME is a valid SOCKSv5 username and PASS is a valid
SOCKSv5 password. PASS represents de new value for the SOCKSv5 password. PASS represents de new value for the
passowrd of the user with the username UNAME. ULEN password of the user with the username UNAME. ULEN
describes the length of UNAME, PLEN describes the describes the length of UNAME, PLEN describes the
length of PASS. length of PASS.
Both UNAME and PASS must only contain printable ASCII
characters other than ':'.
The possible values for CODE are: The possible values for CODE are:
o X'00' OK o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN o X'B0' INVALID TOKEN
o X'C0' INVALID PARAMETER VALUE o X'C0' INVALID PARAMETER VALUE
o X'C1' USER NOT FOUND o X'C1' USER NOT FOUND
o X'D0' VERSION NOT SUPPORTED o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED o X'FF' METHOD NOT SUPPORTED
CMD: X'0A' - ADD USER The INVALID PARAMETER VALUE code will be returned when
ULEN or PLEN is 0 or when there are invalid characters
in either UNAME or PASS.
3.6. CMD: X'05' - ADD USER
Adds a user to the proxy server. Adds a user to the proxy server.
Response comes as with a code representing the output of Response comes with a code representing the output of
the action. the action.
Request: Request:
+-------+-------+---------+--------+-----------+-------+----------+ +-------+-------+---------+--------+-----------+-------+----------+
| VER | TOKEN | CMD | ULEN | UNAME | PLEN | PASS | | VER | TOKEN | CMD | ULEN | UNAME | PLEN | PASS |
+-------+-------+---------+--------+-----------+-------+----------+ +-------+-------+---------+--------+-----------+-------+----------+
| X'01' | 8 | X'0A' | 1 | 1 to 255 | 1 | 1 to 255 | | X'01' | 8 | X'05' | 1 | 1 to 255 | 1 | 1 to 255 |
+-------+-------+---------+--------+-----------+-------+----------+ +-------+-------+---------+--------+-----------+-------+----------+
Response: Response:
@ -356,26 +254,34 @@ CMD: X'0A' - ADD USER
for the username of the new user and PASS represents for the username of the new user and PASS represents
the value for the password of user. ULEN describes the the value for the password of user. ULEN describes the
length of UNAME, PLEN describes the length of PASS. length of UNAME, PLEN describes the length of PASS.
Both UNAME and PASS must only contain printable ASCII
characters other than ':'.
The possible values for CODE are: The possible values for CODE are:
o X'00' OK o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN o X'B0' INVALID TOKEN
o X'C0' INVALID PARAMETER VALUE o X'C0' INVALID PARAMETER VALUE
o X'C2' USER ALREADY EXISTS
o X'D0' VERSION NOT SUPPORTED o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED o X'FF' METHOD NOT SUPPORTED
CMD: X'0B' - DELETE USER The INVALID PARAMETER VALUE code will be returned when
ULEN or PLEN is 0 or when there are invalid characters
in either UNAME or PASS.
3.7. CMD: X'06' - DELETE USER
Deletes a user from the proxy server. Deletes a user from the proxy server.
Response comes as with a code representing the output of Response comes with a code representing the output of
the action. the action.
Request: Request:
+-------+-------+---------+--------+-----------+ +-------+-------+---------+--------+-----------+
| VER | TOKEN | CMD | ULEN | UNAME | | VER | TOKEN | CMD | ULEN | UNAME |
+-------+-------+---------+--------+-----------+ +-------+-------+---------+--------+-----------+
| X'01' | 8 | X'0B' | 1 | 1 to 255 | | X'01' | 8 | X'06' | 1 | 1 to 255 |
+-------+-------+---------+--------+-----------+ +-------+-------+---------+--------+-----------+
Response: Response:
@ -388,21 +294,28 @@ CMD: X'0B' - DELETE USER
UNAME is a valid SOCKSv5 username. UNAME represents UNAME is a valid SOCKSv5 username. UNAME represents
the value for the username of the user to be deleted. the value for the username of the user to be deleted.
ULEN describes the length of UNAME. ULEN describes the length of UNAME.
UNAME must only contain printable ASCII
characters other than ':'.
The possible values for CODE are: The possible values for CODE are:
o X'00' OK o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN o X'B0' INVALID TOKEN
o X'C0' INVALID PARAMETER VALUE o X'C0' INVALID PARAMETER VALUE
o X'C1' USER NOT FOUND o X'C1' USER NOT FOUND
o X'D0' VERSION NOT SUPPORTED o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED o X'FF' METHOD NOT SUPPORTED
CMD: X'0C' - GET PASSWORD DISSECTOR STATUS The INVALID PARAMETER VALUE code will be returned when
ULEN or PLEN is 0 or when there are invalid characters
in either UNAME or PASS.
3.8. CMD: X'07' - GET PASSWORD DISSECTOR STATUS
Requests the status of the password dissector service on Requests the status of the password dissector service on
the proxy server. the proxy server.
Response comes as with a code representing the output of Response comes with a code representing the output of
the action and a STATUS representing the status of the the action and a STATUS representing the status of the
password dissector. password dissector.
@ -410,7 +323,7 @@ CMD: X'0C' - GET PASSWORD DISSECTOR STATUS
+-------+-------+---------+ +-------+-------+---------+
| VER | TOKEN | CMD | | VER | TOKEN | CMD |
+-------+-------+---------+ +-------+-------+---------+
| X'01' | 8 | X'0C' | | X'01' | 8 | X'07' |
+-------+-------+---------+ +-------+-------+---------+
Response: Response:
@ -422,28 +335,29 @@ CMD: X'0C' - GET PASSWORD DISSECTOR STATUS
STATUS represents the status of the password dissector STATUS represents the status of the password dissector
service. If STATUS is X'00' then password dissector service. If STATUS is X'00' then password dissector
service is down. Any other value representes password service is down. Any other value greater than 0 represents
dissector being active. password dissector being active.
The possible values for CODE are: The possible values for CODE are:
o X'00' OK o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN o X'B0' INVALID TOKEN
o X'D0' VERSION NOT SUPPORTED o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED o X'FF' METHOD NOT SUPPORTED
CMD: X'0D' - SET PASSWORD DISSECTOR STATUS 3.9. CMD: X'08' - SET PASSWORD DISSECTOR STATUS
Modifies the status of the password dissector service on Modifies the status of the password dissector service on
the proxy server. the proxy server.
Response comes as with a code representing the output of Response comes with a code representing the output of
the action. the action.
Request: Request:
+-------+-------+---------+--------+ +-------+-------+---------+--------+
| VER | TOKEN | CMD | STATUS | | VER | TOKEN | CMD | STATUS |
+-------+-------+---------+--------+ +-------+-------+---------+--------+
| X'01' | 8 | X'0D' | 1 | | X'01' | 8 | X'08' | 1 |
+-------+-------+---------+--------+ +-------+-------+---------+--------+
Response: Response:
@ -455,23 +369,24 @@ CMD: X'0D' - SET PASSWORD DISSECTOR STATUS
STATUS represents the status of the password dissector STATUS represents the status of the password dissector
service. If STATUS is X'00' then password dissector service. If STATUS is X'00' then password dissector
service will be turned off. Any other value representes service will be turned off. Any other value greater than 0
password dissector being turned on. In case that the represents password dissector being turned on. In case that the
STATUS value is the same of the password dissector service's STATUS value is the same of the password dissector service's
then the instruction will be ignored. then the instruction will be ignored.
The possible values for CODE are: The possible values for CODE are:
o X'00' OK o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN o X'B0' INVALID TOKEN
o X'D0' VERSION NOT SUPPORTED o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED o X'FF' METHOD NOT SUPPORTED
CMD: X'0E' - GET PROXY AUTHENTICATION STATUS 3.10. CMD: X'09' - GET PROXY AUTHENTICATION STATUS
Requests the status of the authentication service on the Requests the status of the authentication service on the
proxy server. proxy server.
Response comes as with a code representing the output of Response comes with a code representing the output of
the action and a STATUS representing the status of the the action and a STATUS representing the status of the
authentication service. authentication service.
@ -479,7 +394,7 @@ CMD: X'0E' - GET PROXY AUTHENTICATION STATUS
+-------+-------+---------+ +-------+-------+---------+
| VER | TOKEN | CMD | | VER | TOKEN | CMD |
+-------+-------+---------+ +-------+-------+---------+
| X'01' | 8 | X'0E' | | X'01' | 8 | X'09' |
+-------+-------+---------+ +-------+-------+---------+
Response: Response:
@ -491,28 +406,29 @@ CMD: X'0E' - GET PROXY AUTHENTICATION STATUS
STATUS represents the status of the authentication STATUS represents the status of the authentication
service. If STATUS is X'00' then authentication service service. If STATUS is X'00' then authentication service
is down. Any other value representes authentication is down. Any other value greater than 0 represents
being active. authentication being active.
The possible values for CODE are: The possible values for CODE are:
o X'00' OK o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN o X'B0' INVALID TOKEN
o X'D0' VERSION NOT SUPPORTED o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED o X'FF' METHOD NOT SUPPORTED
CMD: X'0F' - SET PROXY AUTHENTICATION STATUS 3.11. CMD: X'0A' - SET PROXY AUTHENTICATION STATUS
Modifies the status of the authentication service on the Modifies the status of the authentication service on the
proxy server. proxy server.
Response comes as with a code representing the output of Response comes with a code representing the output of
the action. the action.
Request: Request:
+-------+-------+---------+--------+ +-------+-------+---------+--------+
| VER | TOKEN | CMD | STATUS | | VER | TOKEN | CMD | STATUS |
+-------+-------+---------+--------+ +-------+-------+---------+--------+
| X'01' | 8 | X'0F' | 1 | | X'01' | 8 | X'0A' | 1 |
+-------+-------+---------+--------+ +-------+-------+---------+--------+
Response: Response:
@ -522,332 +438,37 @@ CMD: X'0F' - SET PROXY AUTHENTICATION STATUS
| X'01' | 1 | | X'01' | 1 |
+-------+--------+ +-------+--------+
STATUS represents the status of the password dissector
service. If STATUS is X'00' then
authentication service will be turned off. Any other
value representesauthentication being turned on.
In case that the STATUS value is the same of the
password dissector service's then the instruction will
be ignored.
The possible values for CODE are:
o X'00' OK
o X'B0' INVALID TOKEN
o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED
3. Replies
The SOCKS request information is sent by the client as soon as
it has established a connection to the SOCKS server, and completed
the authentication negotiations. The server evaluates the request,
and returns a reply formed as follows:
+-----+-----+
| VER | REP |
+-----+-----+
| 1 | 1 |
+-----+-----+
Where:
o VER protocol version: X'05'
o REP Reply field:
o X'00' succeeded
o X'01' general SOCKS server failure
o X'02' connection not allowed by ruleset
o X'03' Network unreachable
o X'04' Host unreachable
o X'05' Connection refused
o X'06' TTL expired
o X'07' Command not supported
o X'08' Address type not supported
o X'09' to X'FF' unassigned
9. References The possible values for CODE are:
o X'00' OK
o X'B0' INVALID TOKEN
o X'C0' INVALID PARAMETER VALUE
o X'C1' USER NOT FOUND
o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED
CMD: X'09' - MODIFY PASSWORD
Modifies password of user of proxy server with username
UNAME.
Response comes as with a code representing the output of
the action.
Request:
+-------+-------+---------+--------+-----------+-------+----------+
| VER | TOKEN | CMD | ULEN | UNAME | PLEN | PASS |
+-------+-------+---------+--------+-----------+-------+----------+
| X'01' | 8 | X'09' | 1 | 1 to 255 | 1 | 1 to 255 |
+-------+-------+---------+--------+-----------+-------+----------+
Response:
+-------+--------+
| VER | CODE |
+-------+--------+
| X'01' | 1 |
+-------+--------+
UNAME is a valid SOCKSv5 username and PASS is a valid
SOCKSv5 password. PASS represents de new value for the
passowrd of the user with the username UNAME. ULEN
describes the length of UNAME, PLEN describes the
length of PASS.
The possible values for CODE are:
o X'00' OK
o X'B0' INVALID TOKEN
o X'C0' INVALID PARAMETER VALUE
o X'C1' USER NOT FOUND
o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED
CMD: X'0A' - ADD USER
Adds a user to the proxy server.
Response comes as with a code representing the output of
the action.
Request:
+-------+-------+---------+--------+-----------+-------+----------+
| VER | TOKEN | CMD | ULEN | UNAME | PLEN | PASS |
+-------+-------+---------+--------+-----------+-------+----------+
| X'01' | 8 | X'0A' | 1 | 1 to 255 | 1 | 1 to 255 |
+-------+-------+---------+--------+-----------+-------+----------+
Response:
+-------+--------+
| VER | CODE |
+-------+--------+
| X'01' | 1 |
+-------+--------+
UNAME is a valid SOCKSv5 username and PASS is a
valid SOCKSv5 password. UNAME represents the value
for the username of the new user and PASS represents
the value for the password of user. ULEN describes the
length of UNAME, PLEN describes the length of PASS.
The possible values for CODE are:
o X'00' OK
o X'B0' INVALID TOKEN
o X'C0' INVALID PARAMETER VALUE
o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED
CMD: X'0B' - DELETE USER
Deletes a user from the proxy server.
Response comes as with a code representing the output of
the action.
Request:
+-------+-------+---------+--------+-----------+
| VER | TOKEN | CMD | ULEN | UNAME |
+-------+-------+---------+--------+-----------+
| X'01' | 8 | X'0B' | 1 | 1 to 255 |
+-------+-------+---------+--------+-----------+
Response:
+-------+--------+
| VER | CODE |
+-------+--------+
| X'01' | 1 |
+-------+--------+
UNAME is a valid SOCKSv5 username. UNAME represents
the value for the username of the user to be deleted.
ULEN describes the length of UNAME.
The possible values for CODE are:
o X'00' OK
o X'B0' INVALID TOKEN
o X'C0' INVALID PARAMETER VALUE
o X'C1' USER NOT FOUND
o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED
CMD: X'0C' - GET PASSWORD DISSECTOR STATUS
Requests the status of the password dissector service on
the proxy server.
Response comes as with a code representing the output of
the action and a STATUS representing the status of the
password dissector.
Request:
+-------+-------+---------+
| VER | TOKEN | CMD |
+-------+-------+---------+
| X'01' | 8 | X'0C' |
+-------+-------+---------+
Response:
+-------+--------+--------+
| VER | CODE | STATUS |
+-------+--------+--------+
| X'01' | 1 | 1 |
+-------+--------+--------+
STATUS represents the status of the password dissector
service. If STATUS is X'00' then password dissector
service is down. Any other value representes password
dissector being active.
The possible values for CODE are:
o X'00' OK
o X'B0' INVALID TOKEN
o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED
CMD: X'0D' - SET PASSWORD DISSECTOR STATUS
Modifies the status of the password dissector service on
the proxy server.
Response comes as with a code representing the output of
the action.
Request:
+-------+-------+---------+--------+
| VER | TOKEN | CMD | STATUS |
+-------+-------+---------+--------+
| X'01' | 8 | X'0D' | 1 |
+-------+-------+---------+--------+
Response:
+-------+--------+
| VER | CODE |
+-------+--------+
| X'01' | 1 |
+-------+--------+
STATUS represents the status of the password dissector
service. If STATUS is X'00' then password dissector
service will be turned off. Any other value representes
password dissector being turned on. In case that the
STATUS value is the same of the password dissector service's
then the instruction will be ignored.
The possible values for CODE are:
o X'00' OK
o X'B0' INVALID TOKEN
o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED
CMD: X'0E' - GET PROXY AUTHENTICATION STATUS
Requests the status of the authentication service on the
proxy server.
Response comes as with a code representing the output of
the action and a STATUS representing the status of the
authentication service.
Request:
+-------+-------+---------+
| VER | TOKEN | CMD |
+-------+-------+---------+
| X'01' | 8 | X'0E' |
+-------+-------+---------+
Response:
+-------+--------+--------+
| VER | CODE | STATUS |
+-------+--------+--------+
| X'01' | 1 | 1 |
+-------+--------+--------+
STATUS represents the status of the authentication STATUS represents the status of the authentication
service. If STATUS is X'00' then authentication service service. If STATUS is X'00' then authentication
is down. Any other value representes authentication service will be turned off. Any other value greater
being active. than 0 represents authentication being turned on.
In case that the STATUS value is the same of the
password dissector service's then the instruction
will be ignored.
The possible values for CODE are: The possible values for CODE are:
o X'00' OK o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN o X'B0' INVALID TOKEN
o X'D0' VERSION NOT SUPPORTED o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED o X'FF' METHOD NOT SUPPORTED
CMD: X'0F' - SET PROXY AUTHENTICATION STATUS 4. Considerations
Modifies the status of the authentication service on the If an invalid CMD is requested to a server, it must
proxy server. respond with a package such as:
Response comes as with a code representing the output of
the action.
Request:
+-------+-------+---------+--------+
| VER | TOKEN | CMD | STATUS |
+-------+-------+---------+--------+
| X'01' | 8 | X'0F' | 1 |
+-------+-------+---------+--------+
Response:
+-------+--------+ +-------+--------+
| VER | CODE | | VER | CODE |
+-------+--------+ +-------+--------+
| X'01' | 1 | | X'01' | X'FE' |
+-------+--------+ +-------+--------+
STATUS represents the status of the password dissector Where the CODE X'FE' means that the command is unknown.
service. If STATUS is X'00' then
authentication service will be turned off. Any other
value representesauthentication being turned on.
In case that the STATUS value is the same of the
password dissector service's then the instruction will
be ignored.
The possible values for CODE are: 5. Authors
o X'00' OK Barmasch, Juan Martín (61033)
o X'B0' INVALID TOKEN Bellver, Ezequiel (61268)
o X'D0' VERSION NOT SUPPORTED Lo Coco, Santiago (61301)
o X'FF' METHOD NOT SUPPORTED
3. Replies
The SOCKS request information is sent by the client as soon as
it has established a connection to the SOCKS server, and completed
the authentication negotiations. The server evaluates the request,
and returns a reply formed as follows:
+-----+-----+
| VER | REP |
+-----+-----+
| 1 | 1 |
+-----+-----+
Where:
o VER protocol version: X'05'
o REP Reply field:
o X'00' succeeded
o X'01' general SOCKS server failure
o X'02' connection not allowed by ruleset
o X'03' Network unreachable
o X'04' Host unreachable
o X'05' Connection refused
o X'06' TTL expired
o X'07' Command not supported
o X'08' Address type not supported
o X'09' to X'FF' unassigned
9. References

View File

@ -1,132 +1,121 @@
.\" Macros .\" Macros
.ds PX \s-1POSIX\s+1 .ds PX \s-1POSIX\s+1
.de EXAMPLE .\" Format de los ejemplos .de EXAMPLE .\" Example formta
.RS 10 .RS 10
.BR "\\$1" .BR "\\$1"
.RE .RE
.. ..
.TH socks5d 0.0.0 "24 de mayo 2022" .TH socks5d 1.0 "21 June 2022"
.LO 8 .LO 8
.SH NAME .SH NAME
socks5d \- proxy SOCKS versión 5 con esteroides socks5d \- proxy SOCKS version 5 (BProxy)
.SH SINOPSIS .SH SYNOPSIS
.HP 10 .HP 10
.B socks5d .B socks5d
[ POSIX style options ] [ POSIX style options ]
.SH OPCIONES .SH OPTIONS
.\".IP "\fB\-d\fB"
.\"Establece que debe ejecutar con la configuración predeterminada.
.\".IP
.\"Aquellos servidores donde la configuración sea persistente (el enunciado
.\"no lo requiere) presentan un desafío a la hora de realizar pruebas ya que
.\"se debe conocer la configuración actual.
.\".IP
.\"En esos casos esta opción olvida toda configuración previa y establece
.\"la configuración predeterminada.
.\".IP
.\"La configuración predeterminada consiste en tener apagada las transformaciones.
.IP "\fB-h\fR" .IP "\fB-h\fR"
Imprime la ayuda y termina. Prints help.
.IP "\fB\-l\fB \fIdirección-socks\fR" .IP "\fB\-l\fB \fIsocks-address\fR"
Establece la dirección donde servirá el proxy SOCKS. Establishes address where proxy SOCKS will be served.
Por defecto escucha en todas las interfaces. By default listens in every interface.
.IP "\fB\-N\fB" .IP "\fB\-L\fB \fImanagement-address\fR"
Deshabilita los passwords disectors. Establishes address where management srrver will be served.
By default listens to loopback.
.IP "\fB\-L\fB \fIdirección-de-management\fR" .IP "\fB\-p\fB \fIsocks-port\fR"
Establece la dirección donde servirá el servicio de TCP port where it will listen for incoming SOCKS connections.
management. Por defecto escucha únicamente en loopback. Default value is \fI1080\fR.
.IP "\fB\-p\fB \fIpuerto-local\fR" .IP "\fB\-P\fB \fImanagement-port\fR"
Puerto TCP donde escuchará por conexiones entrantes SOCKS. UDP port where it will listen for incoming Bottler Configuration Protocol connections
Por defecto el valor es \fI1080\fR. Default value is \fI8080\fR.
.IP "\fB\-P\fB \fIpuerto-conf\fR"
Puerto SCTP donde escuchará por conexiones entrante del protocolo
de configuración. Por defecto el valor es \fI8080\fR.
.IP "\fB\-u\fB \fIuser:pass\fR" .IP "\fB\-u\fB \fIuser:pass\fR"
Declara un usuario del proxy con su contraseña. Se puede utilizar Declares a proxy user with its password <uname>:<pass>.
hasta 10 veces. A maximum of 1024 users is established.
.IP "\fB\-v\fB" .IP "\fB\-v\fB"
Imprime información sobre la versión versión y termina. Prints version information.
.SH REGISTRO DE ACCESO .SH ACCESS LOGGING
Registra el uso del proxy en salida estandar. Una conexión por línea. Los campos de una Logs use of proxy server in standard output and file \fIaccess.log\fR. A line per connections.
línea separado por tabs: Each field is delimited by a space:
.IP "\fBfecha\fR" .IP "\fBdate\fR"
que se procesó la conexión en formato ISO-8601. in which the connection has been made in ISO-8601 format.
Ejemplo 2022-06-15T19:56:34Z. Example 2022-06-15T19:56:34Z.
.IP "\fBnombre de usuario\fR" .IP "\fBusername\fR"
que hace el requerimiento. that makes the request. \fIanon\fR if not authenticated.
Ejemplo juan. Example user123.
.IP "\fBtipo de registro\fR" .IP "\fBregister type\fR"
Siempre el caracter A. Always character A.
.IP "\fBdireccion IP origen\fR" .IP "\fBorigin IP address\fR"
desde donde se conectó el usuario. from which the user made the connection.
Ejemplo ::1. Example ::1.
.IP "\fBpuerto origen\fR" .IP "\fBorigin port\fR"
desde donde se conectó el usuario. from which the user made the connection.
Ejemplo 54786. Example 54786.
.IP "\fBdestino\fR" .IP "\fBdestination\fR"
a donde nos conectamos. nombre o dirección IP (según ATY). to which the connection has been made. Name or IP address (according to ATY).
Ejemplo www.itba.edu.ar. Example www.itba.edu.ar.
Ejemplo ::1. Example ::1.
.IP "\fBpuerto destino\fR" a donde nos conectamos. .IP "\fBdestination port\fR"
Ejemplo 443. to which the connection has been made.
Example 443.
.IP "\fBstatus\fR" status SOCKS (0 exito, ...) .IP "\fBstatus\fR"
Status code de SOCKSv5. Ejemplo 0. status SOCKS (0 success, ...)
Status code de SOCKSv5. Example 0.
.SH REGISTRO DE PASSWORDS .SH PASSWORD LOGGING
Registra las credenciales descubiertas en salida estandar. Una credencial por línea. Logs uncovered credentials in standard output and file \fIpasswords.log\fR. One
Los campos de una línea separados por tabs: credential per line. Fields are delimited by spaces:
.IP "\fBfecha\fR" .IP "\fBdate\fR"
que se procesó la conexión en formato ISO-8601. in which the connection has been processed in ISO-8601 format.
Ejemplo 2020-06-15T19:56:34Z. Example 2020-06-15T19:56:34Z.
.IP "\fBnombre de usuario\fR" .IP "\fBusername\fR"
que hace el requerimiento. that makes the request. \fIanon\fR if not authenticated
Ejemplo juan. Example user123.
.IP "\fBtipo de registro\fR" .IP "\fBregister type\fR"
Siempre el caracter P. Always character P.
.IP "\fBprotocolo\fR" .IP "\fBprotocol\fR"
Protocolo del que se trata. HTTP o POP3. Inferred protocol user. If unknown then UNK.
Between partenthesis if suspected.
.IP "\fBdestino\fR" .IP "\fBdestination\fR"
a donde nos conectamos. nombre o dirección IP (según ATY). to which the connection has been made. Name or IP address (according to ATY).
Ejemplo www.itba.edu.ar. Example www.itba.edu.ar.
Ejemplo ::1. Example ::1.
.IP "\fBpuerto destino\fR" a donde nos conectamos. .IP "\fBdestination port\fR"
Ejemplo 443. to which the connection has been made.
Example 443.
.IP "\fBusuario\fR" .IP "\fBdiss_user\fR"
Usuario descubierto. Uncovered username.
.IP "\fBpassword\fR" .IP "\fBdiss_pass\fR"
Password descubierta. Uncovered password.

View File

@ -4,11 +4,12 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#define MAX_USERS 10 #define MAX_USERS 1024
typedef struct user_t { typedef struct user_t {
char * name; char * name;
char * pass; char * pass;
int ulen;
} user_t; } user_t;
struct socks5args { struct socks5args {
@ -19,7 +20,7 @@ struct socks5args {
bool dissector_enabled; bool dissector_enabled;
int nusers; unsigned nusers;
user_t users[MAX_USERS]; user_t users[MAX_USERS];
}; };

View File

@ -13,6 +13,7 @@ enum auth_state {
auth_passwd, auth_passwd,
auth_done, auth_done,
auth_error_unsupported_version, auth_error_unsupported_version,
auth_user_error
}; };
struct auth_parser { struct auth_parser {
@ -21,7 +22,7 @@ struct auth_parser {
void * data; void * data;
enum auth_state state; enum auth_state state;
int user_pos; int user_pos;
char username[255]; char * username;
char idx; char idx;
char password[255]; char password[255];
uint8_t * verified; uint8_t * verified;
@ -40,6 +41,6 @@ extern const char * auth_error(const struct auth_parser *p);
void auth_parser_close(struct auth_parser *p); void auth_parser_close(struct auth_parser *p);
extern int auth_marshall(buffer * b, uint8_t method); extern int auth_marshall(buffer * b, uint8_t status);
#endif #endif

View File

@ -2,7 +2,7 @@
#define BUFFER_H #define BUFFER_H
#include <stdbool.h> #include <stdbool.h>
#include <unistd.h> // size_t, ssize_t #include <unistd.h>
/** /**
* buffer.c - buffer con acceso directo (útil para I/O) que mantiene * buffer.c - buffer con acceso directo (útil para I/O) que mantiene

View File

@ -2,29 +2,25 @@
#define CLIENT_H #define CLIENT_H
#define CMD_GET_METRICS 0x00 #define CMD_GET_METRICS 0x00
#define CMD_GET_BUFFER_SIZE 0x01 #define CMD_GET_USER_PAGES 0x01
#define CMD_SET_BUFFER_SIZE 0x02 #define CMD_LIST_USERS 0x02
#define CMD_GET_TIMEOUT 0x03 #define CMD_MODIFY_USERNAME 0x03
#define CMD_SET_TIMEOUT 0x04 #define CMD_MODIFY_PASSWORD 0x04
#define CMD_GET_USER_PAGES 0x05 #define CMD_ADD_USER 0x05
#define CMD_LIST_USERS 0x06 #define CMD_DELETE_USER 0x06
#define CMD_GET_USER_LAST_CONNECTION 0x07 #define CMD_GET_PASSWORD_DISSECTOR_STATUS 0x07
#define CMD_MODIFY_USERNAME 0x08 #define CMD_MODIFY_PASSWORD_DISSECTOR_STATUS 0x08
#define CMD_MODIFY_PASSWORD 0x09 #define CMD_GET_AUTHENTICATION_STATUS 0x09
#define CMD_ADD_USER 0x0A #define CMD_MODIFY_AUTHENTICATION_STATUS 0x0A
#define CMD_DELETE_USER 0x00B
#define CMD_GET_PASSWORD_DISSECTOR_STATUS 0x0C
#define CMD_MODIFY_PASSWORD_DISSECTOR_STATUS 0x0D
#define CMD_GET_AUTHENTICATION_STATUS 0x0E
#define CMD_MODIFY_AUTHENTICATION_STATUS 0x0F
#define CMD_GET_PROXY_SERVER_STATUS 0x10
#define CMD_CHANGE_PROXY_SERVER_STATUS 0x11
#define CMD_RESTART_PROXY_SERVER 0x12
#define RESPONSE_OK 0x00 #define RESPONSE_OK 0x00
#define RESPONSE_SERVER_ERROR 0xA0
#define RESPONSE_INVALID_TOKEN 0xB0 #define RESPONSE_INVALID_TOKEN 0xB0
#define RESPONSE_INVALID_PARAMETER 0xC0
#define RESPONSE_USER_NOT_FOUND 0xC1
#define RESPONSE_USER_ALREADY_EXISTS 0xC2
#define RESPONSE_VERSION_NOT_SUPPORTED 0xD0 #define RESPONSE_VERSION_NOT_SUPPORTED 0xD0
#define RESPONSE_UNKNOWN_COMMAND 0xFE
#define RESPONSE_CMD_NOT_SUPPORTED 0xFF #define RESPONSE_CMD_NOT_SUPPORTED 0xFF
#endif #endif

View File

@ -8,27 +8,28 @@
#define STR_SIZE 255 #define STR_SIZE 255
#define CMD_GET_METRICS 0x00 #define CMD_GET_METRICS 0x00
#define CMD_GET_BUFFER_SIZE 0x01 #define CMD_GET_USER_PAGES 0x01
#define CMD_SET_BUFFER_SIZE 0x02 #define CMD_LIST_USERS 0x02
#define CMD_GET_TIMEOUT 0x03 #define CMD_MODIFY_USERNAME 0x03
#define CMD_SET_TIMEOUT 0x04 #define CMD_MODIFY_PASSWORD 0x04
#define CMD_GET_USER_PAGES 0x05 #define CMD_ADD_USER 0x05
#define CMD_LIST_USERS 0x06 #define CMD_DELETE_USER 0x006
#define CMD_GET_USER_LAST_CONNECTION 0x07 #define CMD_GET_PASSWORD_DISSECTOR_STATUS 0x07
#define CMD_MODIFY_USERNAME 0x08 #define CMD_MODIFY_PASSWORD_DISSECTOR_STATUS 0x08
#define CMD_MODIFY_PASSWORD 0x09 #define CMD_GET_AUTHENTICATION_STATUS 0x09
#define CMD_ADD_USER 0x0A #define CMD_MODIFY_AUTHENTICATION_STATUS 0x0A
#define CMD_DELETE_USER 0x00B
#define CMD_GET_PASSWORD_DISSECTOR_STATUS 0x0C
#define CMD_MODIFY_PASSWORD_DISSECTOR_STATUS 0x0D
#define CMD_GET_AUTHENTICATION_STATUS 0x0E
#define CMD_MODIFY_AUTHENTICATION_STATUS 0x0F
#define CMD_GET_PROXY_SERVER_STATUS 0x10
#define CMD_CHANGE_PROXY_SERVER_STATUS 0x11
#define CMD_RESTART_PROXY_SERVER 0x12
#define CMD_NOT_SUPPORTED_CMD 0xFF #define CMD_NOT_SUPPORTED_CMD 0xFF
#define CONFIG_OK 0x00
#define CONFIG_SERVER_ERROR 0xA0
#define CONFIG_INVALID_TOKEN 0xB0
#define CONFIG_INVALID_PARAMETER 0xC0
#define CONFIG_USER_NOT_FOUND 0xC1
#define CONFIG_ALREADY_USER_EXISTS 0xC2
#define CONFIG_VERSION_NOT_SUPPORTED 0xD0
#define CONFIG_UNKNOWN_COMMAND 0xFE
enum cmd_state { enum cmd_state {
cmd_version, cmd_version,
cmd_token, cmd_token,
@ -38,6 +39,7 @@ enum cmd_state {
cmd_error_unsupported_version, cmd_error_unsupported_version,
cmd_error_invalid_token, cmd_error_invalid_token,
cmd_error_unsupported_command, cmd_error_unsupported_command,
cmd_error_invalid_parameter
}; };
enum param_state { enum param_state {
@ -78,6 +80,8 @@ struct cmd_parser {
void * parameters; void * parameters;
}; };
extern bool is_valid(uint8_t c);
void cmd_parser_init(struct cmd_parser * p); void cmd_parser_init(struct cmd_parser * p);
enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b); enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b);
@ -86,10 +90,8 @@ enum cmd_state cmd_consume(buffer * b, struct cmd_parser * p, bool * errored);
bool cmd_is_done(enum cmd_state state, bool * errored); bool cmd_is_done(enum cmd_state state, bool * errored);
extern const char * cmd_error(const struct cmd_parser * p); extern uint8_t cmd_error(const struct cmd_parser * p);
void cmd_parser_close(struct cmd_parser * p); void cmd_parser_close(struct cmd_parser * p);
//extern int cmd_marshall(buffer * b, uint8_t method);
#endif #endif

View File

@ -4,7 +4,7 @@
#include "stm.h" #include "stm.h"
#include "cmd.h" #include "cmd.h"
#define BUFF_SIZE 1024 #define BUFF_SIZE 4096
struct cmd_st { struct cmd_st {
buffer *rb, *wb; buffer *rb, *wb;

View File

@ -80,6 +80,4 @@ extern int request_marshall(buffer * b, const enum socks_response_status status)
enum socks_response_status errno_to_socks(int e); enum socks_response_status errno_to_socks(int e);
enum socks_response_status cmd_resolve(struct request * request, struct sockaddr ** originaddr, socklen_t * origin_len, int * domain);
#endif #endif

View File

@ -1,12 +1,18 @@
#ifndef SERVER_H #ifndef SERVER_H
#define SERVER_H #define SERVER_H
#define PAGE_SIZE 5
#define USERNAME_MAX_LEN 256
int findUser(char * username); int findUser(char * username);
int check_password(int idx, char * password); int check_password(int idx, char * password);
bool add_user(char * username, char * password); int add_user(char * username, char * password);
bool modify_username(char * old_uname, char * new_uname); int modify_username(char * old_uname, char * new_uname);
bool modify_password(char * uname, char * new_pwd); int modify_password(char * uname, char * new_pwd);
bool delete_user(char * uname); bool delete_user(char * uname);
size_t get_user_pages();
bool get_users(char * buff, int page);
uint8_t verify_token(uint64_t token);
#endif #endif

View File

@ -30,28 +30,35 @@ static void user(char * s, user_t * user) {
*p = 0; *p = 0;
p++; p++;
char * uname = malloc(strlen(s) + 1); char * uname = malloc(strlen(s) + 1);
if (uname == NULL)
return;
strcpy(uname, s); strcpy(uname, s);
char * pass = malloc(strlen(p) + 1); char * pass = malloc(strlen(p) + 1);
if (pass == NULL) {
free(uname);
return;
}
strcpy(pass, p); strcpy(pass, p);
user->name = uname; user->name = uname;
user->pass = pass; user->pass = pass;
user->ulen = strlen(uname) + 1;
} }
} }
static void version(void) { static void version(void) {
fprintf(stderr, "BProxy v0.0\nITBA Protocolos de Comunicación 2021/1 -- Grupo 7\nVer LICENSE.md\n"); fprintf(stderr, "BProxy v1.0\nITBA Protocolos de Comunicación 2021/1 -- Group 7\nSee LICENSE.md\n");
} }
static void usage(const char *progname) { static void usage(const char *progname) {
fprintf(stderr, fprintf(stderr,
"Usage: %s [OPTION]\n\n" "Usage: %s [OPTION]\n\n"
" -h Imprime la ayuda y termina.\n" " -h Prints help.\n"
" -l <SOCKS addr> Dirección donde servirá el proxy SOCKS.\n" " -l <SOCKS addr> Address where proxy SOCKS will be served.\n"
" -L <conf addr> Dirección donde servirá el servicio de management.\n" " -L <conf addr> Address where management service will be served.\n"
" -p <SOCKS port> Puerto entrante conexiones SOCKS.\n" " -p <SOCKS port> Port for incoming SOCKS connections.\n"
" -P <conf port> Puerto entrante conexiones configuracion.\n" " -P <conf port> Port for incoming configuration connections.\n"
" -u <name>:<pass> Usuario y contraseña de usuario que puede usar el proxy. Hasta 500.\n" " -u <name>:<pass> Username and password of proxy user. Up to 1024.\n"
" -v Imprime información sobre la versión y termina.\n\n", " -v Prints version information.\n\n",
progname); progname);
exit(1); exit(1);
} }
@ -62,7 +69,7 @@ void parse_args(const int argc, char ** argv, struct socks5args * args) {
args->socks_addr = NULL; args->socks_addr = NULL;
args->socks_port = 1080; args->socks_port = 1080;
args->mng_addr = "127.0.0.1"; args->mng_addr = NULL;
args->mng_port = 8080; args->mng_port = 8080;
args->dissector_enabled = true; args->dissector_enabled = true;
@ -70,7 +77,7 @@ void parse_args(const int argc, char ** argv, struct socks5args * args) {
int c; int c;
int nusers = 0; int nusers = 0;
while (true) { while (true) {
c = getopt(argc, argv, "hl:L:Np:P:u:v"); c = getopt(argc, argv, "hl:L:p:P:u:v");
if (c == -1) if (c == -1)
break; break;
@ -84,14 +91,11 @@ void parse_args(const int argc, char ** argv, struct socks5args * args) {
case 'L': case 'L':
args->mng_addr = optarg; args->mng_addr = optarg;
break; break;
case 'N':
args->dissector_enabled = false;
break;
case 'p': case 'p':
args->socks_port = port(optarg); args->socks_port = port(optarg);
break; break;
case 'P': case 'P':
args->mng_port = port(optarg); args->mng_port = port(optarg);
break; break;
case 'u': case 'u':
if (nusers >= MAX_USERS) { if (nusers >= MAX_USERS) {
@ -106,7 +110,7 @@ void parse_args(const int argc, char ** argv, struct socks5args * args) {
version(); version();
exit(0); exit(0);
default: default:
fprintf(stderr, "unknown argument %d.\n", c); fprintf(stderr, "Unknown argument %d.\n", c);
exit(1); exit(1);
} }
} }

View File

@ -5,7 +5,12 @@
#include "auth.h" #include "auth.h"
void auth_parser_init(struct auth_parser *p) { // es imprimible y distinto de ':'
bool is_valid(uint8_t c) {
return c >= 0x20 && c <= 0x7E && c != 0x3A;
}
void auth_parser_init(struct auth_parser * p) {
p->state = auth_version; p->state = auth_version;
p->remaining = 0; p->remaining = 0;
} }
@ -28,6 +33,9 @@ enum auth_state auth_parser_feed(struct auth_parser * p, uint8_t b) {
} }
break; break;
case auth_uname: case auth_uname:
if (!is_valid(b)) {
p->state = auth_user_error;
}
*(p->username + p->idx++) = (char) b; *(p->username + p->idx++) = (char) b;
p->remaining--; p->remaining--;
@ -50,6 +58,9 @@ enum auth_state auth_parser_feed(struct auth_parser * p, uint8_t b) {
} }
break; break;
case auth_passwd: case auth_passwd:
if (!is_valid(b)) {
p->state = auth_user_error;
}
*(p->password + p->idx++) = (char) b; *(p->password + p->idx++) = (char) b;
p->remaining--; p->remaining--;
@ -64,9 +75,10 @@ enum auth_state auth_parser_feed(struct auth_parser * p, uint8_t b) {
break; break;
case auth_done: case auth_done:
case auth_error_unsupported_version: case auth_error_unsupported_version:
case auth_user_error:
break; break;
default: default:
fprintf(stderr, "unknown state %d\n", p->state); fprintf(stderr, "Unknown state %d\n", p->state);
abort(); abort();
} }
@ -77,6 +89,7 @@ extern bool auth_is_done(const enum auth_state state, bool * errored) {
bool ret = true; bool ret = true;
switch (state) { switch (state) {
case auth_user_error:
case auth_error_unsupported_version: case auth_error_unsupported_version:
if (0 != errored) { if (0 != errored) {
*errored = true; *errored = true;
@ -96,7 +109,10 @@ extern const char * auth_error(const struct auth_parser *p) {
char * ret; char * ret;
switch (p->state) { switch (p->state) {
case auth_error_unsupported_version: case auth_error_unsupported_version:
ret = "unsupported version"; ret = "Unsupported version";
break;
case auth_user_error:
ret = "User error";
break; break;
default: default:
ret = ""; ret = "";
@ -123,7 +139,7 @@ extern enum auth_state auth_consume(buffer * b, struct auth_parser *p, bool * er
return st; return st;
} }
extern int auth_marshall(buffer * b, const uint8_t status) { extern int auth_marshall(buffer * b, uint8_t status) {
size_t n; size_t n;
uint8_t * buff = buffer_write_ptr(b, &n); uint8_t * buff = buffer_write_ptr(b, &n);
if (n < 2) { if (n < 2) {

View File

@ -59,7 +59,6 @@ buffer_read_adv(buffer *b, const ssize_t bytes) {
assert(b->read <= b->write); assert(b->read <= b->write);
if (b->read == b->write) { if (b->read == b->write) {
// compactacion poco costosa
buffer_compact(b); buffer_compact(b);
} }
} }
@ -88,7 +87,6 @@ buffer_write(buffer *b, uint8_t c) {
void void
buffer_compact(buffer *b) { buffer_compact(buffer *b) {
if (b->data == b->read) { if (b->data == b->read) {
// nada por hacer
} else if (b->read == b->write) { } else if (b->read == b->write) {
b->read = b->data; b->read = b->data;
b->write = b->data; b->write = b->data;

View File

@ -14,348 +14,518 @@
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <fcntl.h> #include <fcntl.h>
#include <getopt.h> #include <getopt.h>
#include <arpa/inet.h>
#include <netutils.h>
#include "client.h" #include "client.h"
#define MAX_SIZE 524 #define MAX_SIZE 524
#define MAX_RECV_SIZE 1024 #define MAX_RECV_SIZE 1500
#define PAGE_SIZE 5
#define MAX_USERNAME_LEN 256
#define N(x) (sizeof(x)/sizeof((x)[0])) #define N(x) (sizeof(x)/sizeof((x)[0]))
static void version(void) { static unsigned short get_port(const char *s) {
fprintf(stderr, "BProxy v1.0\nITBA Protocolos de Comunicación 2021/1 -- Grupo 7\nVer LICENSE.md\n"); char *end = 0;
const long sl = strtol(s, &end, 10);
if (end == s || '\0' != *end || ((LONG_MIN == sl || LONG_MAX == sl) && ERANGE == errno) || sl < 0 || sl > USHRT_MAX) {
fprintf(stderr, "Port should be in the range of 1-65536: %s\n", s);
exit(1);
return 1;
}
return (unsigned short) sl;
} }
static void usage(const char *progname) { static void version(void) {
fprintf(stderr, fprintf(stdout, "BProxy v1.0\nITBA Protocolos de Comunicación 2021/1 -- Group 7\nSee LICENSE.md\n");
"Usage: %s [token] [OPTION]\n\n" }
" -h Imprime la ayuda y termina.\n"
" -m Obtener métricas del servidor.\n" static void usage(const char * progname) {
" -b Obtener el tamaño del buffer.\n" fprintf(stdout,
" -B <value> Modificar el tamaño del buffer.\n" "Usage: %s [OPTION]\n\n"
" -t Obtener el valor del timeout.\n" " -h Prints help\n"
" -T <value> Modificar el valor del timeout.\n" " -v Prints client version\n"
" -f Obtener cantidad de páginas de nombres de usuario.\n" " [TOKEN] -m Get server metrics\n"
" -u <page> Obtener nombres de usuario de la página especificada.\n" " [TOKEN] -f Get amount of user pages\n"
" -l <name> Obtener la última conexión del usuario específicado.\n" " [TOKEN] -u <page> Get users in a page\n"
" -c <name>:<new_name> Nombre de usuario y nuevo nombre de usuario\n" " [TOKEN] -c <name>:<new_name> Change username from <name> to <new_name>\n"
" -p <name>:<new_pass> Nombre de usuario y su nueva contraseña\n" " [TOKEN] -p <name>:<new_pass> Change user' with username <name> password\n"
" -n <name>:<pass> Nombre de usuario y contraseña del usuario que desea ser agregado\n" " [TOKEN] -n <name>:<pass> Adds user to proxy server\n"
" -d <name> Nombre del usuario que desea ser borrado\n" " [TOKEN] -d <name> Deletes user from proxy server\n"
" -s Obtener el estado del disector de contraseñas POP3.\n" " [TOKEN] -s Get password dissector status\n"
" -S <estado> Modificar el estado del disector de contraseñas POP3.\n" " [TOKEN] -S <state> Modify password dissector status\n"
" -a Obtener el estado de la autorización del proxy.\n" " [TOKEN] -a Get proxy authentication status\n"
" -A <estado> Modificar el estado de la autorización del proxy.\n" " [TOKEN] -L <conf addr> Address of management service.\n"
" -z Obtener el estado del servidor proxy.\n" " [TOKEN] -P <conf port> Port of management service.\n"
" -Z <estado> Modificar el estado del servidor proxy.\n" " [TOKEN] -A <state> Modify proxy authentication status\n"
" -r Reinicia el servidor\n\n", "Where TOKEN is an 8-byte unsigned integer\n\n",
progname); progname);
exit(1); exit(1);
} }
// aceptar -L uint8_t parse_args(int argc, char ** argv, uint8_t * buffer, char ** address, unsigned short * port) {
uint8_t parse_args(int argc, char ** argv, uint8_t * buffer) {
int c; int c;
if (argc <= 1 || argv[1][0] == '-') { if (argc <= 1) {
fprintf(stderr, "You must enter a valid token.\n"); fprintf(stderr, "You must enter a valid token\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
uint64_t token = atol(argv[1]);
buffer[0] = 0x01;
buffer[1] = token>>56; bool sent_token = false;
buffer[2] = (uint8_t) (token>>48);
buffer[3] = (uint8_t) (token>>40);
buffer[4] = (uint8_t) (token>>32);
buffer[5] = (uint8_t) (token>>24);
buffer[6] = (uint8_t) (token>>16);
buffer[7] = (uint8_t) (token>>8);
buffer[8] = (uint8_t) token;
for (int i = 1; i < argc; ++i) { if (argv[1][0] != '-') {
argv[i] = argv[i+1]; uint64_t token = atol(argv[1]);
}
argc--; buffer[0] = 0x01;
c = getopt(argc, argv, "hmbtfsazrB:T:l:u:c:A:S:p:n:d:Z:"); buffer[1] = token>>56;
// retorna : o ? si le falta el argumento buffer[2] = (uint8_t) (token>>48);
if (c == -1) { buffer[3] = (uint8_t) (token>>40);
fprintf(stderr, "One option required\n"); buffer[4] = (uint8_t) (token>>32);
exit(EXIT_FAILURE); // TODO: chequear bien buffer[5] = (uint8_t) (token>>24);
return 0xFF; buffer[6] = (uint8_t) (token>>16);
buffer[7] = (uint8_t) (token>>8);
buffer[8] = (uint8_t) token;
for (int i = 1; i < argc; ++i) {
argv[i] = argv[i+1];
}
argc--;
sent_token = true;
} }
if (optind < 3 && argc > 2) { char args = 0;
fprintf(stderr, "Only one option allowed\n"); bool Lpresent = false, Ppresent = false;
exit(EXIT_FAILURE); while (args < 3) {
} if (args == 1) {
if (!(Lpresent || Ppresent))
uint16_t value; break;
uint8_t ulen, plen, nulen; }
char * p; if (args == 2) {
switch (c) { if (!(Lpresent && Ppresent))
case 'h': break;
usage(argv[0]); }
break;
case 'm': c = getopt(argc, argv, "hvmfu:c:p:n:d:sS:aA:L:P:");
buffer[9] = 0x00; if (c == -1) {
break; fprintf(stderr, "A valid option is required\n");
case 'b':
buffer[9] = 0x01;
break;
case 'B':
buffer[9] = 0x02;
buffer[9] = (uint16_t) atoi(optarg);
break;
case 't':
buffer[9] = 0x03;
break;
case 'T':
buffer[9] = 0x04;
value = atoi(optarg);
buffer[10] = value >> 8;
buffer[11] = (uint8_t) value;
break;
case 'f':
buffer[9] = 0x05;
break;
case 'u':
buffer[9] = 0x06;
value = atoi(optarg);
buffer[10] = value >> 8;
buffer[11] = (uint8_t) value;
break;
case 'l':
buffer[9] = 0x07;
ulen = strlen(optarg);
buffer[10] = ulen;
strcat((char *) buffer, optarg);
break;
case 'c':
buffer[9] = 0x08;
char *n = strchr(optarg, ':');
*n = 0;
n++;
ulen = strlen(optarg);
nulen = strlen(n);
buffer[10] = ulen;
strcat((char *) buffer, optarg);
buffer[11+ulen] = nulen;
strcat((char *) buffer, n);
break;
case 'p':
buffer[9] = 0x09;
p = strchr(optarg, ':');
*p = 0;
p++;
ulen = strlen(optarg);
plen = strlen(p);
buffer[10] = ulen;
strcat((char *) buffer, optarg);
buffer[11+ulen] = plen;
strcat((char *) buffer, p);
break;
case 'n':
buffer[9] = 0x0A;
p = strchr(optarg, ':');
*p = 0;
p++;
ulen = strlen(optarg);
plen = strlen(p);
buffer[10] = ulen;
strcat((char *) buffer, optarg);
buffer[11+ulen] = plen;
strcat((char *) buffer, p);
break;
case 'd':
buffer[9] = 0x0B;
ulen = strlen(optarg);
buffer[10] = ulen;
strcat((char *) buffer, optarg);
break;
case 's':
buffer[9] = 0x0C;
break;
case 'S':
buffer[9] = 0x0D;
buffer[10] = (uint8_t) atoi(optarg);
break;
case 'a':
buffer[9] = 0x0E;
break;
case 'A':
buffer[9] = 0x0F;
buffer[10] = (uint8_t) atoi(optarg);
break;
case 'z':
buffer[9] = 0x10;
break;
case 'Z':
buffer[9] = 0x11;
buffer[10] = (uint8_t) atoi(optarg);
break;
case 'r':
buffer[9] = 0x12;
break;
case 'v':
version();
exit(EXIT_SUCCESS);
default:
fprintf(stderr, "Unknown argument %d.\n", c);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}
uint16_t value;
size_t ulen, plen, nulen;
char * p;
switch (c) {
case 'h':
usage(argv[0]);
case 'v':
version();
exit(EXIT_SUCCESS);
case 'm':
if (!sent_token) {
fprintf(stderr, "Token required for desired command\n");
exit(EXIT_FAILURE);
}
buffer[9] = CMD_GET_METRICS;
break;
case 'f':
if (!sent_token) {
fprintf(stderr, "Token required for desired command\n");
exit(EXIT_FAILURE);
}
buffer[9] = CMD_GET_USER_PAGES;
break;
case 'u':
if (!sent_token) {
fprintf(stderr, "Token required for desired command\n");
exit(EXIT_FAILURE);
}
buffer[9] = CMD_LIST_USERS;
value = atoi(optarg);
buffer[10] = value >> 8;
buffer[11] = (uint8_t) value;
break;
case 'c':
if (!sent_token) {
fprintf(stderr, "Token required for desired command\n");
exit(EXIT_FAILURE);
}
buffer[9] = CMD_MODIFY_USERNAME;
char *n = strchr(optarg, ':');
if (n == NULL) {
fprintf(stderr, "New username not found\n");
exit(EXIT_FAILURE);
}
*n = 0;
n++;
ulen = strlen(optarg);
if (ulen == 0 || ulen > 255) {
fprintf(stderr, "Username length must be between 1 and 255\n");
exit(EXIT_FAILURE);
}
nulen = strlen(n);
if (nulen == 0 || nulen > 255) {
fprintf(stderr, "New username length must be between 1 and 255\n");
exit(EXIT_FAILURE);
}
buffer[10] = (uint8_t) ulen;
strcat((char *) buffer, optarg);
buffer[11+ulen] = (uint8_t) nulen;
strcat((char *) buffer, n);
break;
case 'p':
if (!sent_token) {
fprintf(stderr, "Token required for desired command\n");
exit(EXIT_FAILURE);
}
buffer[9] = CMD_MODIFY_PASSWORD;
p = strchr(optarg, ':');
if (p == NULL) {
fprintf(stderr, "New password not found\n");
exit(EXIT_FAILURE);
}
*p = 0;
p++;
ulen = strlen(optarg);
if (ulen == 0 || ulen > 255) {
fprintf(stderr, "Username length must be between 1 and 255\n");
exit(EXIT_FAILURE);
}
plen = strlen(p);
if (plen == 0 || plen > 255) {
fprintf(stderr, "Password length must be between 1 and 255\n");
exit(EXIT_FAILURE);
}
buffer[10] = (uint8_t) ulen;
strcat((char *) buffer, optarg);
buffer[11+ulen] = (uint8_t) plen;
strcat((char *) buffer, p);
break;
case 'n':
if (!sent_token) {
fprintf(stderr, "Token required for desired command\n");
exit(EXIT_FAILURE);
}
buffer[9] = CMD_ADD_USER;
p = strchr(optarg, ':');
if (p == NULL) {
fprintf(stderr, "New password not found\n");
exit(EXIT_FAILURE);
}
*p = 0;
p++;
ulen = strlen(optarg);
if (ulen == 0 || ulen > 255) {
fprintf(stderr, "Username length must be between 1 and 255\n");
exit(EXIT_FAILURE);
}
plen = strlen(p);
if (plen == 0 || plen > 255) {
fprintf(stderr, "Password length must be between 1 and 255\n");
exit(EXIT_FAILURE);
}
buffer[10] = (uint8_t) ulen;
strcat((char *) buffer, optarg);
buffer[11+ulen] = (uint8_t) plen;
strcat((char *) buffer, p);
break;
case 'd':
if (!sent_token) {
fprintf(stderr, "Token required for desired command\n");
exit(EXIT_FAILURE);
}
buffer[9] = CMD_DELETE_USER;
ulen = strlen(optarg);
if (ulen == 0 || ulen > 255) {
fprintf(stderr, "Username length must be between 1 and 255\n");
exit(EXIT_FAILURE);
}
buffer[10] = (uint8_t) ulen;
strcat((char *) buffer, optarg);
break;
case 's':
if (!sent_token) {
fprintf(stderr, "Token required for desired command\n");
exit(EXIT_FAILURE);
}
buffer[9] = CMD_GET_PASSWORD_DISSECTOR_STATUS;
break;
case 'S':
if (!sent_token) {
fprintf(stderr, "Token required for desired command\n");
exit(EXIT_FAILURE);
}
buffer[9] = CMD_MODIFY_PASSWORD_DISSECTOR_STATUS;
buffer[10] = (uint8_t) atoi(optarg);
break;
case 'a':
if (!sent_token) {
fprintf(stderr, "Token required for desired command\n");
exit(EXIT_FAILURE);
}
buffer[9] = CMD_GET_AUTHENTICATION_STATUS;
break;
case 'A':
if (!sent_token) {
fprintf(stderr, "Token required for desired command\n");
exit(EXIT_FAILURE);
}
buffer[9] = CMD_MODIFY_AUTHENTICATION_STATUS;
buffer[10] = (uint8_t) atoi(optarg);
break;
case 'L':
if (!sent_token) {
fprintf(stderr, "Token required for desired command\n");
exit(EXIT_FAILURE);
}
Lpresent = true;
*address = optarg;
break;
case 'P':
if (!sent_token) {
fprintf(stderr, "Token required for desired command\n");
exit(EXIT_FAILURE);
}
Ppresent = true;
*port = get_port(optarg);
break;
default:
fprintf(stderr, "Unknown argument %d\n", c);
exit(EXIT_FAILURE);
}
args++;
} }
return buffer[9]; return buffer[9];
} }
void parse_response(uint8_t * buffer, uint8_t cmd) { int parse_response(uint8_t * buffer, uint8_t cmd) {
if (buffer[0] != 0x01) { if (buffer[0] != 0x01) {
fprintf(stderr, "Incorrect response version.\n"); fprintf(stderr, "Incorrect response version\n");
return EXIT_FAILURE;
} }
uint32_t now_conn = 0, total_conn = 0; uint32_t now_conn = 0, total_conn = 0;
uint64_t bytes = 0; uint64_t bytes = 0;
uint16_t pages, k = 0, users = 0;
switch (buffer[1]) { switch (buffer[1]) {
case RESPONSE_OK: case RESPONSE_OK:
fprintf(stdout, "Success.\n");
switch (cmd) { switch (cmd) {
case CMD_GET_METRICS: case CMD_GET_METRICS:
fprintf(stdout, "Metrics:\n"); fprintf(stdout, "Metrics:\n");
total_conn += buffer[2]; total_conn += buffer[2];
total_conn <<= 24; total_conn <<= 8;
total_conn += buffer[3]; total_conn += buffer[3];
total_conn <<= 16; total_conn <<= 8;
total_conn += buffer[4]; total_conn += buffer[4];
total_conn <<= 8; total_conn <<= 8;
total_conn += buffer[5]; total_conn += buffer[5];
now_conn += buffer[6]; now_conn += buffer[6];
now_conn <<= 24; now_conn <<= 8;
now_conn += buffer[7]; now_conn += buffer[7];
now_conn <<= 16; now_conn <<= 8;
now_conn += buffer[8]; now_conn += buffer[8];
now_conn <<= 8; now_conn <<= 8;
now_conn += buffer[9]; now_conn += buffer[9];
bytes += buffer[10]; bytes += buffer[10];
bytes <<= 56; bytes <<= 8;
bytes += buffer[11]; bytes += buffer[11];
bytes <<= 48; bytes <<= 8;
bytes += buffer[12]; bytes += buffer[12];
bytes <<= 40; bytes <<= 8;
bytes += buffer[13]; bytes += buffer[13];
bytes <<= 32; bytes <<= 8;
bytes += buffer[14]; bytes += buffer[14];
bytes <<= 24; bytes <<= 8;
bytes += buffer[15]; bytes += buffer[15];
bytes <<= 16; bytes <<= 8;
bytes += buffer[16]; bytes += buffer[16];
bytes <<= 8; bytes <<= 8;
bytes += buffer[17]; bytes += buffer[17];
fprintf(stdout, "\tTotal connections: %u\n\tCurrent connections: %u\n\tTotal bytes transferred: %lu\n", total_conn, now_conn, bytes); fprintf(stdout, "\tTotal connections: %u\n\tCurrent connections: %u\n\tTotal bytes transferred: %lu\n", total_conn, now_conn, bytes);
break; break;
/*
case CMD_GET_BUFFER_SIZE:
break;
case CMD_SET_BUFFER_SIZE:
break;
case CMD_GET_TIMEOUT:
break;
case CMD_SET_TIMEOUT:
break;
*/
case CMD_GET_USER_PAGES: case CMD_GET_USER_PAGES:
fprintf(stdout, "User pages: ...\n"); // buffer[2 y 3]; pages = buffer[2];
pages <<= 8;
pages += buffer[3];
fprintf(stdout, "User pages: %u\n", pages);
break; break;
case CMD_LIST_USERS: case CMD_LIST_USERS:
fprintf(stdout, "Users... \n"); fprintf(stdout, "Users:\n");
break; while (users < PAGE_SIZE && !(k > 2 && buffer[k - 1] == '\n' && buffer[k] == '\n')) {
case CMD_GET_USER_LAST_CONNECTION: if (buffer[k] == '\n')
fprintf(stdout, "Users... \n"); users++;
putchar(buffer[k++]);
}
break; break;
case CMD_GET_PASSWORD_DISSECTOR_STATUS: case CMD_GET_PASSWORD_DISSECTOR_STATUS:
fprintf(stdout, "Password dissector status: %s\n", buffer[2] ? "ON" : "OFF"); fprintf(stdout, "Password dissector status: %s\n", buffer[2] ? "ON" : "OFF");
break; break;
case CMD_MODIFY_PASSWORD_DISSECTOR_STATUS:
break;
case CMD_GET_AUTHENTICATION_STATUS: case CMD_GET_AUTHENTICATION_STATUS:
fprintf(stdout, "Proxy authentication status: %s\n", buffer[2] ? "ON" : "OFF"); fprintf(stdout, "Proxy authentication status: %s\n", buffer[2] ? "ON" : "OFF");
break; break;
case CMD_MODIFY_PASSWORD_DISSECTOR_STATUS:
case CMD_MODIFY_AUTHENTICATION_STATUS: case CMD_MODIFY_AUTHENTICATION_STATUS:
break;
case CMD_GET_PROXY_SERVER_STATUS:
fprintf(stdout, "Proxy server status: %s\n", buffer[2] ? "ON" : "OFF");
break;
case CMD_MODIFY_USERNAME: case CMD_MODIFY_USERNAME:
case CMD_MODIFY_PASSWORD: case CMD_MODIFY_PASSWORD:
case CMD_ADD_USER: case CMD_ADD_USER:
case CMD_DELETE_USER: case CMD_DELETE_USER:
case CMD_CHANGE_PROXY_SERVER_STATUS: fprintf(stdout, "Success\n");
case CMD_RESTART_PROXY_SERVER:
break; break;
default: default:
break; break;
} }
return EXIT_SUCCESS;
case RESPONSE_SERVER_ERROR:
fprintf(stderr, "ERROR - Server error\n");
break; break;
case RESPONSE_INVALID_TOKEN: case RESPONSE_INVALID_TOKEN:
fprintf(stdout, "Invalid token.\n"); fprintf(stderr, "ERROR - Invalid token\n");
break;
case RESPONSE_INVALID_PARAMETER:
fprintf(stderr, "ERROR - Parameter value is invalid for requested command\n");
break; break;
case RESPONSE_CMD_NOT_SUPPORTED: case RESPONSE_CMD_NOT_SUPPORTED:
fprintf(stdout, "Command not supported.\n"); fprintf(stderr, "ERROR - Command not supported\n");
break; break;
case RESPONSE_VERSION_NOT_SUPPORTED: case RESPONSE_VERSION_NOT_SUPPORTED:
fprintf(stdout, "Version not supported.\n"); fprintf(stderr, "ERROR - Version not supported\n");
break;
case RESPONSE_UNKNOWN_COMMAND:
fprintf(stderr, "ERROR - Unknown command\n");
break;
case RESPONSE_USER_NOT_FOUND:
fprintf(stderr, "ERROR - Specified user not found\n");
break;
case RESPONSE_USER_ALREADY_EXISTS:
fprintf(stderr, "ERROR - Username already exists\n");
break; break;
default: default:
fprintf(stderr, "ERROR - Unknown response status\n");
break; break;
} }
return EXIT_FAILURE;
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
const char *err_msg = NULL; const char *err_msg = NULL;
uint8_t * recv_buffer = NULL;
uint8_t buffer[MAX_SIZE] = {0};
char * address = NULL;
unsigned short port = 0;
uint8_t cmd = parse_args(argc, argv, buffer, &address, &port);
int client = -1;
struct sockaddr_in addr; unsigned char buf[sizeof(struct in6_addr)];
memset(&addr, 0, sizeof(addr)); int domain = AF_INET;
addr.sin_family = AF_INET; if (address != NULL) {
addr.sin_addr.s_addr = htonl(INADDR_ANY); if (inet_pton(AF_INET6, address, buf)) {
addr.sin_port = htons(8080); domain = AF_INET6;
} else if (!inet_pton(AF_INET, address, buf)) {
err_msg = "Incorrect network address";
goto finally;
}
}
const int client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); struct sockaddr_in addr_ipv4;
if (domain == AF_INET) {
memset(&addr_ipv4, 0, sizeof(addr_ipv4));
addr_ipv4.sin_family = AF_INET;
if (address != NULL) {
if (inet_pton(AF_INET, address, &addr_ipv4.sin_addr) <= 0) {
err_msg = "Incorrect network address";
goto finally;
}
} else {
addr_ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
}
if (port != 0) {
addr_ipv4.sin_port = htons(port);
} else {
addr_ipv4.sin_port = htons(8080);
}
}
struct sockaddr_in6 addr_ipv6;
if (domain == AF_INET6) {
memset(&addr_ipv6, 0, sizeof(addr_ipv6));
addr_ipv6.sin6_family = AF_INET6;
if (inet_pton(AF_INET6, address, &addr_ipv6.sin6_addr) <= 0) {
err_msg = "Incorrect network address";
goto finally;
}
if (port != 0) {
addr_ipv6.sin6_port = htons(port);
} else {
addr_ipv6.sin6_port = htons(8080);
}
}
client = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
if (client < 0) { if (client < 0) {
err_msg = "Unable to create UDP socket"; err_msg = "Unable to create UDP socket";
goto finally; goto finally;
} }
if (connect(client, (struct sockaddr *) &addr, sizeof(addr)) < 0) { char buff[SOCKADDR_TO_HUMAN_MIN + 1];
err_msg = "Unable to connect to UDP socket"; if (domain == AF_INET) {
goto finally; sockaddr_to_human(buff, SOCKADDR_TO_HUMAN_MIN, (const struct sockaddr *) &addr_ipv4);
fprintf(stdout, "Connecting to %s\n\n", buff);
if (connect(client, (struct sockaddr *) &addr_ipv4, sizeof(addr_ipv4)) < 0) {
err_msg = "Unable to connect to UDP socket";
goto finally;
}
} else {
sockaddr_to_human(buff, SOCKADDR_TO_HUMAN_MIN, (const struct sockaddr *) &addr_ipv6);
fprintf(stdout, "Connecting to %s\n\n", buff);
if (connect(client, (struct sockaddr *) &addr_ipv6, sizeof(addr_ipv6)) < 0) {
err_msg = "Unable to connect to UDP socket";
goto finally;
}
} }
uint8_t buffer[MAX_SIZE] = {0}; ssize_t sent;
uint8_t cmd = parse_args(argc, argv, buffer); if (domain == AF_INET) {
sent = sendto(client, buffer, N(buffer), 0, NULL, sizeof(addr_ipv4));
ssize_t sent = sendto(client, buffer, N(buffer), 0, NULL, sizeof(addr)); if (sent < 0) {
if (sent < 0) { err_msg = "Unable to send cmd";
err_msg = "Unable to send cmd"; goto finally;
}
}
else {
sent = sendto(client, buffer, N(buffer), 0, NULL, sizeof(addr_ipv6));
if (sent < 0) {
err_msg = "Unable to send cmd";
goto finally;
}
}
recv_buffer = calloc(1, MAX_RECV_SIZE);
if (recv_buffer == NULL) {
err_msg = "Malloc failed";
goto finally; goto finally;
} }
uint8_t * recv_buffer = calloc(1, MAX_RECV_SIZE);
ssize_t received = recvfrom(client, recv_buffer, MAX_RECV_SIZE, 0, NULL, NULL); ssize_t received = recvfrom(client, recv_buffer, MAX_RECV_SIZE, 0, NULL, NULL);
if (received < 0) { if (received < 0) {
err_msg = "Unable to receive cmd"; err_msg = "Unable to receive cmd";
goto finally; goto finally;
} }
parse_response(recv_buffer, cmd); int ret = parse_response(recv_buffer, cmd);
err_msg = NULL; err_msg = NULL;
int ret = EXIT_SUCCESS;
finally: finally:
free(recv_buffer); if (recv_buffer != NULL) {
free(recv_buffer);
}
if (err_msg) { if (err_msg) {
perror(err_msg); perror(err_msg);
ret = EXIT_FAILURE; ret = EXIT_FAILURE;

View File

@ -2,7 +2,6 @@
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h>
#include "cmd.h" #include "cmd.h"
@ -40,16 +39,22 @@ enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b) {
switch (p->param_state) { switch (p->param_state) {
case param_ulen: case param_ulen:
p->remaining = b; p->remaining = b;
if (p->remaining == 0)
p->state = cmd_error_invalid_parameter;
p->param_state = param_uname; p->param_state = param_uname;
break; break;
case param_uname: case param_uname:
if (!is_valid(b)) {
p->state = cmd_error_invalid_parameter;
break;
}
*(p->username + p->idx++) = (char) b; *(p->username + p->idx++) = (char) b;
p->remaining--; p->remaining--;
if (p->remaining == 0) { if (p->remaining == 0) {
*(p->username + p->idx++) = 0; *(p->username + p->idx++) = 0;
p->idx = 0; p->idx = 0;
if (*p->cmd == CMD_DELETE_USER || *p->cmd == CMD_GET_USER_LAST_CONNECTION) if (*p->cmd == CMD_DELETE_USER)
p->state = cmd_done; p->state = cmd_done;
else if (*p->cmd == CMD_MODIFY_USERNAME) else if (*p->cmd == CMD_MODIFY_USERNAME)
p->param_state = param_new_ulen; p->param_state = param_new_ulen;
@ -59,9 +64,15 @@ enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b) {
break; break;
case param_plen: case param_plen:
p->remaining = b; p->remaining = b;
if (p->remaining == 0)
p->state = cmd_error_invalid_parameter;
p->param_state = param_passwd; p->param_state = param_passwd;
break; break;
case param_passwd: case param_passwd:
if (!is_valid(b)) {
p->state = cmd_error_invalid_parameter;
break;
}
*(p->password + p->idx++) = (char) b; *(p->password + p->idx++) = (char) b;
p->remaining--; p->remaining--;
@ -77,9 +88,15 @@ enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b) {
break; break;
case param_new_ulen: case param_new_ulen:
p->remaining = b; p->remaining = b;
if (p->remaining == 0)
p->state = cmd_error_invalid_parameter;
p->param_state = param_new_uname; p->param_state = param_new_uname;
break; break;
case param_new_uname: case param_new_uname:
if (!is_valid(b)) {
p->state = cmd_error_invalid_parameter;
break;
}
*(p->new_username + p->idx++) = (char) b; *(p->new_username + p->idx++) = (char) b;
p->remaining--; p->remaining--;
@ -101,10 +118,11 @@ enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b) {
case cmd_done: case cmd_done:
case cmd_error_unsupported_version: case cmd_error_unsupported_version:
case cmd_error_unsupported_command: case cmd_error_unsupported_command:
case cmd_error_invalid_parameter:
case cmd_error_invalid_token: case cmd_error_invalid_token:
break; break;
default: default:
fprintf(stderr, "unknown state %d\n", p->state); fprintf(stderr, "Unknown state %d\n", p->state);
abort(); abort();
} }
return p->state; return p->state;
@ -114,7 +132,10 @@ extern bool cmd_is_done(const enum cmd_state state, bool * errored) {
bool ret = true; bool ret = true;
switch (state) { switch (state) {
case cmd_error_unsupported_command:
case cmd_error_invalid_token:
case cmd_error_unsupported_version: case cmd_error_unsupported_version:
case cmd_error_invalid_parameter:
if (0 != errored) { if (0 != errored) {
*errored = true; *errored = true;
} }
@ -129,20 +150,23 @@ extern bool cmd_is_done(const enum cmd_state state, bool * errored) {
return ret; return ret;
} }
extern const char * cmd_error(const struct cmd_parser * p) { extern uint8_t cmd_error(const struct cmd_parser * p) {
char * ret; uint8_t ret;
switch (p->state) { switch (p->state) {
case cmd_error_unsupported_version: case cmd_error_unsupported_version:
ret = "Unsupported version"; ret = CONFIG_VERSION_NOT_SUPPORTED;
break; break;
case cmd_error_unsupported_command: case cmd_error_unsupported_command:
ret = "Unsupported command"; ret = CMD_NOT_SUPPORTED_CMD;
break; break;
case cmd_error_invalid_token: case cmd_error_invalid_token:
ret = "Invalid token"; ret = CONFIG_INVALID_TOKEN;
break;
case cmd_error_invalid_parameter:
ret = CONFIG_INVALID_PARAMETER;
break; break;
default: default:
ret = ""; ret = CONFIG_OK;
break; break;
} }
@ -151,7 +175,6 @@ extern const char * cmd_error(const struct cmd_parser * p) {
extern void cmd_parser_close(struct cmd_parser * p) {} extern void cmd_parser_close(struct cmd_parser * p) {}
extern enum cmd_state cmd_consume(buffer * b, struct cmd_parser * p, bool * errored) { extern enum cmd_state cmd_consume(buffer * b, struct cmd_parser * p, bool * errored) {
enum cmd_state st = p->state; enum cmd_state st = p->state;
@ -165,17 +188,3 @@ extern enum cmd_state cmd_consume(buffer * b, struct cmd_parser * p, bool * erro
return st; return st;
} }
//extern int cmd_marshall(buffer * b, const uint8_t status) {
// size_t n;
// uint8_t * buff = buffer_write_ptr(b, &n);
// if (n < 2) {
// return -1;
// }
//
// buff[0] = 0x01;
// buff[1] = status;
//
// buffer_write_adv(b, 2);
// return 2;
//}

View File

@ -14,13 +14,12 @@
#define N(x) (sizeof(x)/sizeof((x)[0])) #define N(x) (sizeof(x)/sizeof((x)[0]))
#define TOKEN 0x0FF1CEDEADB00B1E
static void on_token(struct cmd_parser * p, const uint64_t token) { static void on_token(struct cmd_parser * p, const uint64_t token) {
*p->verified = (token - (uint64_t) TOKEN == 0); *p->verified = verify_token(token);
p->state = cmd_cmd; p->state = cmd_cmd;
if (!*p->verified) if (!*p->verified) {
p->state = cmd_error_invalid_token; p->state = cmd_error_invalid_token;
}
} }
static void on_cmd(struct cmd_parser * p, const uint8_t cmd) { static void on_cmd(struct cmd_parser * p, const uint8_t cmd) {
@ -29,38 +28,14 @@ static void on_cmd(struct cmd_parser * p, const uint8_t cmd) {
case CMD_GET_METRICS: case CMD_GET_METRICS:
*selected = CMD_GET_METRICS; *selected = CMD_GET_METRICS;
break; break;
case CMD_GET_BUFFER_SIZE:
*selected = CMD_GET_BUFFER_SIZE;
break;
case CMD_SET_BUFFER_SIZE:
*selected = CMD_SET_BUFFER_SIZE;
p->state = cmd_parameters;
p->remaining = 2;
p->param_state = param_value;
break;
case CMD_GET_TIMEOUT:
*selected = CMD_GET_TIMEOUT;
break;
case CMD_SET_TIMEOUT:
*selected = CMD_SET_TIMEOUT;
p->state = cmd_parameters;
p->remaining = 2;
p->param_state = param_value;
break;
case CMD_GET_USER_PAGES: case CMD_GET_USER_PAGES:
*selected = CMD_GET_USER_PAGES; *selected = CMD_GET_USER_PAGES;
break; break;
case CMD_LIST_USERS: case CMD_LIST_USERS:
*selected = CMD_LIST_USERS; *selected = CMD_LIST_USERS;
p->state = cmd_parameters; p->state = cmd_parameters;
p->param_state = param_byte; p->param_state = param_value;
p->remaining = 1; p->remaining = 2;
break;
case CMD_GET_USER_LAST_CONNECTION:
*selected = CMD_GET_USER_LAST_CONNECTION;
p->state = cmd_parameters;
p->param_state = param_ulen;
p->remaining = 1;
break; break;
case CMD_MODIFY_USERNAME: case CMD_MODIFY_USERNAME:
*selected = CMD_MODIFY_USERNAME; *selected = CMD_MODIFY_USERNAME;
@ -104,35 +79,11 @@ static void on_cmd(struct cmd_parser * p, const uint8_t cmd) {
p->param_state = param_byte; p->param_state = param_byte;
p->remaining = 1; p->remaining = 1;
break; break;
case CMD_GET_PROXY_SERVER_STATUS:
*selected = CMD_GET_PROXY_SERVER_STATUS;
break;
case CMD_CHANGE_PROXY_SERVER_STATUS:
*selected = CMD_CHANGE_PROXY_SERVER_STATUS;
p->state = cmd_parameters;
p->param_state = param_byte;
p->remaining = 1;
break;
case CMD_RESTART_PROXY_SERVER:
*selected = CMD_RESTART_PROXY_SERVER;
break;
default: default:
*selected = CMD_NOT_SUPPORTED_CMD; *selected = CMD_NOT_SUPPORTED_CMD;
} }
} }
//void cmd_process(struct cmd_st * d) {
//// unsigned ret = WRITE;
//
// uint8_t m = d->status;
// const uint8_t r = m ? 0x00 : 0xFF;
// if (cmd_marshall(d->wb, (enum cmd_response_status) r) == -1) {
//// ret = ERROR;
// }
//
//// return ret;
//}
#define ATTACHMENT(key) ((struct config *)(key)->data) #define ATTACHMENT(key) ((struct config *)(key)->data)
static void config_read_init(struct selector_key * key) { static void config_read_init(struct selector_key * key) {
@ -154,7 +105,6 @@ static void config_read_init(struct selector_key * key) {
cmd_parser_init(&d->parser); cmd_parser_init(&d->parser);
} }
ssize_t cmd_process(struct selector_key *key, buffer * b) { ssize_t cmd_process(struct selector_key *key, buffer * b) {
struct cmd_st *d = &ATTACHMENT(key)->client.cmd; struct cmd_st *d = &ATTACHMENT(key)->client.cmd;
@ -165,23 +115,20 @@ ssize_t cmd_process(struct selector_key *key, buffer * b) {
return 0; return 0;
} }
uint8_t status;
ssize_t i = 0; ssize_t i = 0;
buff[i++] = 0x01; buff[i++] = 0x01;
if (!d->verified) { if (d->status == CMD_NOT_SUPPORTED_CMD || d->status == CONFIG_VERSION_NOT_SUPPORTED || d->status == CONFIG_INVALID_PARAMETER || d->status == CONFIG_INVALID_TOKEN) {
buff[i++] = 0xB0;
buffer_write_adv(b, i);
return i;
}
if (d->status == 0xFF || d->status == 0xD0 || d->status == 0xC0) {
buff[i++] = d->status; buff[i++] = d->status;
buffer_write_adv(b, i); buffer_write_adv(b, i);
return i; return i;
} }
int ret;
uint64_t bytes; uint64_t bytes;
uint32_t total_conn, now_conn; uint32_t total_conn, now_conn;
uint16_t pages, k = 0, users = 0, status = 1;
uint8_t buffer[PAGE_SIZE * USERNAME_MAX_LEN];
buff[i++] = 0x00; buff[i++] = 0x00;
switch (d->cmd) { switch (d->cmd) {
@ -210,31 +157,56 @@ ssize_t cmd_process(struct selector_key *key, buffer * b) {
buff[i++] = (uint8_t) bytes; buff[i++] = (uint8_t) bytes;
break; break;
// case CMD_GET_BUFFER_SIZE:
// break;
// case CMD_SET_BUFFER_SIZE:
// break;
// case CMD_GET_TIMEOUT:
// break;
// case CMD_SET_TIMEOUT:
// break;
case CMD_GET_USER_PAGES: case CMD_GET_USER_PAGES:
pages = get_user_pages();
buff[i++] = (uint8_t) (pages >> 8);
buff[i++] = (uint8_t) pages;
break; break;
case CMD_LIST_USERS: case CMD_LIST_USERS:
break; if (!get_users((char *) buffer, d->value - 1)) {
case CMD_GET_USER_LAST_CONNECTION: buff[status] = CONFIG_INVALID_PARAMETER;
break;
}
while (users < PAGE_SIZE && !(k > 0 && buffer[k - 1] == '\n' && buffer[k] == '\n')) {
if (buffer[k] == '\n') {
users++;
}
buff[i++] = buffer[k++];
}
buff[i++] = buffer[k];
break; break;
case CMD_MODIFY_USERNAME: case CMD_MODIFY_USERNAME:
status = modify_username(d->username, d->new_username); ret = modify_username(d->username, d->new_username);
if (!ret) {
buff[status] = CONFIG_USER_NOT_FOUND;
}
else if (ret == -1) {
buff[status] = CONFIG_SERVER_ERROR;
}
break; break;
case CMD_MODIFY_PASSWORD: case CMD_MODIFY_PASSWORD:
status = modify_password(d->username, d->password); ret = modify_password(d->username, d->password);
if (!ret) {
buff[status] = CONFIG_USER_NOT_FOUND;
}
else if (ret == -1) {
buff[status] = CONFIG_SERVER_ERROR;
}
break; break;
case CMD_ADD_USER: case CMD_ADD_USER:
status = add_user(d->username, d->password); ret = add_user(d->username, d->password);
if (ret == -1) {
buff[status] = CONFIG_SERVER_ERROR;
}
else if (ret == -2) {
buff[status] = CONFIG_ALREADY_USER_EXISTS;
}
break; break;
case CMD_DELETE_USER: case CMD_DELETE_USER:
status = delete_user(d->username); if (!delete_user(d->username)) {
buff[status] = CONFIG_USER_NOT_FOUND;
break;
}
break; break;
case CMD_GET_PASSWORD_DISSECTOR_STATUS: case CMD_GET_PASSWORD_DISSECTOR_STATUS:
buff[i++] = get_pass_dissector_status(); buff[i++] = get_pass_dissector_status();
@ -248,15 +220,8 @@ ssize_t cmd_process(struct selector_key *key, buffer * b) {
case CMD_MODIFY_AUTHENTICATION_STATUS: case CMD_MODIFY_AUTHENTICATION_STATUS:
set_auth_status(d->byte); set_auth_status(d->byte);
break; break;
case CMD_GET_PROXY_SERVER_STATUS:
break;
case CMD_CHANGE_PROXY_SERVER_STATUS:
break;
case CMD_RESTART_PROXY_SERVER:
break;
default: default:
fprintf(stderr, "Unknown command\n"); buff[status] = CONFIG_UNKNOWN_COMMAND;
buff[i++] = 0xFE;
break; break;
} }
@ -264,7 +229,6 @@ ssize_t cmd_process(struct selector_key *key, buffer * b) {
return i; return i;
} }
// TODO: manejo de errores
void config_read(struct selector_key *key) { void config_read(struct selector_key *key) {
struct cmd_st *d = &ATTACHMENT(key)->client.cmd; struct cmd_st *d = &ATTACHMENT(key)->client.cmd;
bool error = false; bool error = false;
@ -281,7 +245,9 @@ void config_read(struct selector_key *key) {
buffer_write_adv(d->rb, n); buffer_write_adv(d->rb, n);
const enum cmd_state st = cmd_consume(d->rb, &d->parser, &error); const enum cmd_state st = cmd_consume(d->rb, &d->parser, &error);
if (cmd_is_done(st, &error)) { if (cmd_is_done(st, 0)) {
if (error)
d->status = cmd_error(&d->parser);
if (SELECTOR_SUCCESS == selector_set_interest_key(key, OP_WRITE)) { if (SELECTOR_SUCCESS == selector_set_interest_key(key, OP_WRITE)) {
if (cmd_process(key, d->wb) == 0) if (cmd_process(key, d->wb) == 0)
return; return;

View File

@ -40,7 +40,7 @@ enum hello_state hello_parser_feed(struct hello_parser * p, uint8_t b) {
case hello_error_unsupported_version: case hello_error_unsupported_version:
break; break;
default: default:
fprintf(stderr, "unknown state %d\n", p->state); fprintf(stderr, "Unknown state %d\n", p->state);
abort(); abort();
} }

View File

@ -37,18 +37,16 @@ struct parser_event * parser_feed(struct parser *p, const uint8_t c) {
const struct parser_state_transition *state = p->def->states[p->state]; const struct parser_state_transition *state = p->def->states[p->state];
const size_t n = p->def->states_n[p->state]; const size_t n = p->def->states_n[p->state];
bool matched = false; bool matched;
for (unsigned i = 0; i < n ; i++) { for (unsigned i = 0; i < n ; i++) {
const int when = state[i].when; const int when = state[i].when;
if (state[i].when <= 0xFF) { if (state[i].when <= 0xFF) {
matched = (c == when); matched = (c == when);
} else if (state[i].when == ANY) { } else if (state[i].when == (int) ANY) {
matched = true; matched = true;
} else if (state[i].when > 0xFF) {
matched = (type & when);
} else { } else {
matched = false; matched = (type & when);
} }
if (matched) { if (matched) {

View File

@ -54,18 +54,11 @@ struct parser_definition * parser_utils_strcmpi(const char *s) {
free(transitions); free(transitions);
struct parser_definition * def = calloc(1, sizeof(struct parser_definition)); struct parser_definition * def = calloc(1, sizeof(struct parser_definition));
// struct parser_definition def = {
// .start_state = 0,
// .states_count = 0,
// .states = NULL,
// .states_n = NULL,
// };
return def; return def;
} }
// estados fijos // Estados fijos
const size_t st_eq = n; const size_t st_eq = n;
const size_t st_neq = n + 1; const size_t st_neq = n + 1;
@ -106,13 +99,6 @@ struct parser_definition * parser_utils_strcmpi(const char *s) {
def->states = (struct parser_state_transition **) states; def->states = (struct parser_state_transition **) states;
def->states_n = (size_t *) nstates; def->states_n = (size_t *) nstates;
// struct parser_definition def = {
// .start_state = 0,
// .states_count = n + 2,
// // .states = (const struct parser_state_transition **) states,
// // .states_n = (const size_t *) nstates,
// };
return def; return def;
} }

View File

@ -212,46 +212,6 @@ extern int request_marshall(buffer * b, const enum socks_response_status status)
return 10; return 10;
} }
// TODO REPLACE CON sockaddr_storage
enum socks_response_status cmd_resolve(struct request * request, struct sockaddr ** originaddr, socklen_t * origin_len, int * domain) {
enum socks_response_status ret = status_general_SOCKS_server_failure;
*domain = AF_INET;
struct sockaddr * addr = 0x00;
socklen_t addrlen = 0;
switch (request->dest_addr_type) {
case socks_req_addr_domain: {
// TODO: SOPORTAR DOMAIN QUE VIENE CON IPV6
struct hostent * hp = gethostbyname(request->dest_addr.fqdn);
if (hp == 0) {
memset(&request->dest_addr, 0x00, sizeof(request->dest_addr));
break;
}
request->dest_addr.ipv4.sin_family = hp->h_addrtype;
memcpy((char *) &request->dest_addr.ipv4.sin_addr, *hp->h_addr_list, hp->h_length);
}
case socks_req_addr_ipv4:
// *domain = AF_INET;
addr = (struct sockaddr *)&(request->dest_addr.ipv4);
addrlen = sizeof(request->dest_addr.ipv4);
request->dest_addr.ipv4.sin_port = request->dest_port;
break;
case socks_req_addr_ipv6:
*domain = AF_INET6;
addr = (struct sockaddr *) &(request->dest_addr.ipv6);
addrlen = sizeof(request->dest_addr.ipv6);
request->dest_addr.ipv6.sin6_port = request->dest_port;
break;
default:
return status_address_type_not_supported;
}
*originaddr = addr;
*origin_len = addrlen;
return ret;
}
enum socks_response_status errno_to_socks(int e) { enum socks_response_status errno_to_socks(int e) {
enum socks_response_status ret = status_general_SOCKS_server_failure; enum socks_response_status ret = status_general_SOCKS_server_failure;
switch (e) { switch (e) {

View File

@ -20,6 +20,7 @@
#include "socks5nio.h" #include "socks5nio.h"
#include "confignio.h" #include "confignio.h"
#include "buffer.h" #include "buffer.h"
#include "server.h"
#define N(x) (sizeof(x)/sizeof((x)[0])) #define N(x) (sizeof(x)/sizeof((x)[0]))
@ -31,17 +32,42 @@ static void sigterm_handler(const int signal) {
} }
static struct socks5args * args; static struct socks5args * args;
uint64_t config_token;
int main(int argc, char **argv) { int main(int argc, char **argv) {
char * token = getenv("BPROXY_TOKEN");
if (token != NULL) {
config_token = strtoul(token, NULL, 16);
}
else {
fprintf(stderr, "No token defined\n");
exit(EXIT_FAILURE);
}
args = malloc(sizeof(struct socks5args)); args = malloc(sizeof(struct socks5args));
parse_args(argc, argv, args); parse_args(argc, argv, args);
printf("\033[0;36m");
printf("$$\\\n"
"$$ |\n"
"$$ |\n"
"$$$$$$$\\ $$$$$$\\ $$$$$$\\ $$$$$$\\ $$\\ $$\\ $$\\ $$\\ \n"
"$$ __$$\\ $$ __$$\\ $$ __$$\\ $$ __$$\\ \\$$\\ $$ |$$ | $$ |\n"
"$$ | $$ |$$ / $$ |$$ | \\__|$$ / $$ | \\$$$$ / $$ | $$ |\n"
"$$ | $$ |$$ | $$ |$$ | $$ | $$ | $$ $$< $$ | $$ |\n"
"$$$$$$$ |$$$$$$$ |$$ | \\$$$$$$ |$$ /\\$$\\ \\$$$$$$$ |\n"
"\\_______/ $$ ____/ \\__| \\______/ \\__/ \\__| \\____$$ |\n"
" $$ | $$\\ $$ |\n"
" $$ | \\$$$$$$ |\n"
" \\__| \\______/\n\n");
printf("\033[0m");
close(STDIN_FILENO); close(STDIN_FILENO);
const char *err_msg = NULL; const char *err_msg = NULL;
selector_status ss = SELECTOR_SUCCESS; selector_status ss = SELECTOR_SUCCESS;
fd_selector selector = NULL; fd_selector selector = NULL;
struct config * config_ret = NULL;
struct config * config_ret_ipv6 = NULL;
// ------ // ------
// TCP // TCP
@ -78,7 +104,10 @@ int main(int argc, char **argv) {
goto finally; goto finally;
} }
fprintf(stdout, "Listening on TCP port %u\n", args->socks_port); if (args->socks_addr != NULL)
fprintf(stdout, "Proxy SOCKS listening on %s:%u TCP\n", args->socks_addr, args->socks_port);
else
fprintf(stdout, "Proxy SOCKS listening on 0.0.0.0:%u TCP\n", args->socks_port);
setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)); setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int));
@ -114,7 +143,10 @@ int main(int argc, char **argv) {
goto finally; goto finally;
} }
fprintf(stdout, "Listening on TCP port %u\n", args->socks_port); if (args->socks_addr != NULL)
fprintf(stdout, "Proxy SOCKS listening on %s:%u TCP\n", args->socks_addr, args->socks_port);
else
fprintf(stdout, "Proxy SOCKS listening on :::%u TCP\n", args->socks_port);
setsockopt(server_ipv6, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)); setsockopt(server_ipv6, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int));
setsockopt(server_ipv6, SOL_IPV6, IPV6_V6ONLY, &(int) { 1 }, sizeof(int)); setsockopt(server_ipv6, SOL_IPV6, IPV6_V6ONLY, &(int) { 1 }, sizeof(int));
@ -134,41 +166,112 @@ int main(int argc, char **argv) {
// UDP // UDP
// ------ // ------
int domain_udp = -1;
if (args->mng_addr != NULL) {
if (inet_pton(AF_INET, args->mng_addr, buf)) {
domain_udp = AF_INET;
} else if (inet_pton(AF_INET6, args->mng_addr, buf)) {
domain_udp = AF_INET6;
}
}
struct sockaddr_in udp_addr; struct sockaddr_in udp_addr;
memset(&udp_addr, 0, sizeof(udp_addr)); int udp_server;
udp_addr.sin_family = AF_INET; if (domain_udp == AF_INET || domain_udp == -1) {
if (inet_pton(AF_INET, args->mng_addr, &udp_addr.sin_addr) <= 0) { memset(&udp_addr, 0, sizeof(udp_addr));
err_msg = "Incorrect network address"; udp_addr.sin_family = AF_INET;
goto finally; if (domain_udp == AF_INET) {
} if (inet_pton(AF_INET, args->mng_addr, &udp_addr.sin_addr) <= 0) {
// udp_addr.sin_addr.s_addr = htonl(INADDR_ANY); err_msg = "Incorrect network address";
udp_addr.sin_port = htons(args->mng_port); goto finally;
}
} else {
udp_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
}
udp_addr.sin_port = htons(args->mng_port);
const int udp_server = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); udp_server = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (udp_server < 0) { if (udp_server < 0) {
err_msg = "Unable to create UDP socket"; err_msg = "Unable to create UDP socket";
goto finally; goto finally;
}
if (args->mng_addr != NULL)
fprintf(stdout, "Management service listening on %s:%u UDP\n", args->mng_addr, args->mng_port);
else
fprintf(stdout, "Management service listening on 127.0.0.1:%u UDP\n", args->mng_port);
setsockopt(udp_server, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int));
if (bind(udp_server, (struct sockaddr *) &udp_addr, sizeof(udp_addr)) < 0) {
err_msg = "Unable to bind UDP socket";
goto finally;
}
if (fcntl(udp_server, F_SETFL, O_NONBLOCK) < 0) {
err_msg = "Unable to put UDP socket into non-blocking mode";
goto finally;
}
config_ret = malloc(sizeof(struct config));
if (config_ret == NULL) {
err_msg = "Malloc failed";
goto finally;
}
memset(config_ret, 0x00, sizeof(*config_ret));
buffer_init(&config_ret->read_buffer, N(config_ret->raw_buff_a), config_ret->raw_buff_a);
buffer_init(&config_ret->write_buffer, N(config_ret->raw_buff_b), config_ret->raw_buff_b);
} }
fprintf(stdout, "Listening on UDP port %u\n", args->mng_port); struct sockaddr_in6 udp_addr_ipv6;
int udp_server_ipv6;
if (domain_udp == AF_INET6 || domain_udp == -1) {
memset(&udp_addr_ipv6, 0, sizeof(udp_addr_ipv6));
udp_addr_ipv6.sin6_family = AF_INET6;
if (domain_udp == AF_INET6) {
if (inet_pton(AF_INET6, args->mng_addr, &udp_addr_ipv6.sin6_addr) <= 0) {
err_msg = "Incorrect network address";
goto finally;
}
} else {
udp_addr_ipv6.sin6_addr = in6addr_loopback;
}
udp_addr_ipv6.sin6_port = htons(args->mng_port);
setsockopt(udp_server, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)); udp_server_ipv6 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (udp_server_ipv6 < 0) {
err_msg = "Unable to create UDP socket";
goto finally;
}
if (bind(udp_server, (struct sockaddr *) &udp_addr, sizeof(udp_addr)) < 0) { if (args->mng_addr != NULL)
err_msg = "Unable to bind UDP socket"; fprintf(stdout, "Management service listening on %s:%u UDP\n", args->mng_addr, args->mng_port);
goto finally; else
fprintf(stdout, "Management service listening on ::1:%u UDP\n", args->mng_port);
setsockopt(udp_server_ipv6, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int));
setsockopt(udp_server_ipv6, SOL_IPV6, IPV6_V6ONLY, &(int) { 1 }, sizeof(int));
if (bind(udp_server_ipv6, (struct sockaddr *) &udp_addr_ipv6, sizeof(udp_addr_ipv6)) < 0) {
err_msg = "Unable to bind UDP socket";
goto finally;
}
if (fcntl(udp_server_ipv6, F_SETFL, O_NONBLOCK) < 0) {
err_msg = "Unable to put UDP socket into non-blocking mode";
goto finally;
}
config_ret_ipv6 = malloc(sizeof(struct config));
if (config_ret_ipv6 == NULL) {
err_msg = "Malloc failed";
goto finally;
}
memset(config_ret_ipv6, 0x00, sizeof(*config_ret));
buffer_init(&config_ret_ipv6->read_buffer, N(config_ret_ipv6->raw_buff_a), config_ret_ipv6->raw_buff_a);
buffer_init(&config_ret_ipv6->write_buffer, N(config_ret_ipv6->raw_buff_b), config_ret_ipv6->raw_buff_b);
} }
if (fcntl(udp_server, F_SETFL, O_NONBLOCK) < 0) {
err_msg = "Unable to put UDP socket into non-blocking mode";
goto finally;
}
struct config * config_ret = malloc(sizeof(struct config));
memset(config_ret, 0x00, sizeof(*config_ret));
buffer_init(&config_ret->read_buffer, N(config_ret->raw_buff_a), config_ret->raw_buff_a);
buffer_init(&config_ret->write_buffer, N(config_ret->raw_buff_b), config_ret->raw_buff_b);
signal(SIGTERM, sigterm_handler); signal(SIGTERM, sigterm_handler);
signal(SIGINT, sigterm_handler); signal(SIGINT, sigterm_handler);
@ -221,20 +324,35 @@ int main(int argc, char **argv) {
} }
} }
if (selector_fd_set_nio(udp_server) == -1) {
err_msg = "Getting config socket flags";
goto finally;
}
const struct fd_handler config = { const struct fd_handler config = {
.handle_read = config_read, .handle_read = config_read,
.handle_write = NULL, .handle_write = NULL,
.handle_close = NULL, .handle_close = NULL,
}; };
ss = selector_register(selector, udp_server, &config, OP_READ, config_ret); if (domain_udp == AF_INET || domain_udp == -1) {
if (ss != SELECTOR_SUCCESS) { if (selector_fd_set_nio(udp_server) == -1) {
err_msg = "Registering fd"; err_msg = "Getting config socket flags";
goto finally; goto finally;
}
ss = selector_register(selector, udp_server, &config, OP_READ, config_ret);
if (ss != SELECTOR_SUCCESS) {
err_msg = "Registering fd";
goto finally;
}
}
if (domain_udp == AF_INET6 || domain_udp == -1) {
if (selector_fd_set_nio(udp_server_ipv6) == -1) {
err_msg = "Getting config socket flags";
goto finally;
}
ss = selector_register(selector, udp_server_ipv6, &config, OP_READ, config_ret_ipv6);
if (ss != SELECTOR_SUCCESS) {
err_msg = "Registering fd";
goto finally;
}
} }
for(;!done;) { for(;!done;) {
@ -249,15 +367,18 @@ int main(int argc, char **argv) {
err_msg = "Closing"; err_msg = "Closing";
} }
for (int i = 0; i < args->nusers; i++) { int ret = 0;
finally:
for (unsigned int i = 0; i < args->nusers; i++) {
free(args->users[i].name); free(args->users[i].name);
free(args->users[i].pass); free(args->users[i].pass);
} }
free(args); free(args);
free(config_ret); if (config_ret != NULL)
free(config_ret);
if (config_ret_ipv6 != NULL)
free(config_ret_ipv6);
int ret = 0;
finally:
if (ss != SELECTOR_SUCCESS) { if (ss != SELECTOR_SUCCESS) {
fprintf(stderr, "%s: %s\n", (err_msg == NULL) ? "": err_msg, ss == SELECTOR_IO ? strerror(errno) : selector_error(ss)); fprintf(stderr, "%s: %s\n", (err_msg == NULL) ? "": err_msg, ss == SELECTOR_IO ? strerror(errno) : selector_error(ss));
ret = 2; ret = 2;
@ -275,11 +396,20 @@ finally:
if (server >= 0) { if (server >= 0) {
close(server); close(server);
} }
if (server_ipv6 >= 0) {
close(server_ipv6);
}
if (udp_server > 0) {
close(udp_server);
}
if (udp_server_ipv6 > 0) {
close(udp_server);
}
return ret; return ret;
} }
int findUser(char * username) { int findUser(char * username) {
for (int i = 0; i < args->nusers; i++) { for (unsigned int i = 0; i < args->nusers; i++) {
if (!strcmp(args->users[i].name, username)) if (!strcmp(args->users[i].name, username))
return i; return i;
} }
@ -290,36 +420,53 @@ int check_password(int idx, char * password) {
return !strcmp(args->users[idx].pass, password); return !strcmp(args->users[idx].pass, password);
} }
bool add_user(char * username, char * password) { int add_user(char * username, char * password) {
if (args->nusers < MAX_USERS) { if (findUser(username) == -1) {
user_t * user = malloc(sizeof(user_t)); if (args->nusers < MAX_USERS) {
user->name = malloc(strlen(username) + 1); int len = strlen(username) + 1;
strcpy(user->name, username); args->users[args->nusers].name = malloc(len);
user->pass = malloc(strlen(password) + 1); if (args->users[args->nusers].name == NULL) {
strcpy(user->pass, password); return -1;
args->users[args->nusers] = *user; }
args->nusers++; strcpy(args->users[args->nusers].name, username);
return true; args->users[args->nusers].pass = malloc(strlen(password) + 1);
if (args->users[args->nusers].pass == NULL) {
return -1;
}
strcpy(args->users[args->nusers].pass, password);
args->users[args->nusers].ulen = len;
args->nusers++;
return 0;
}
return -1;
} }
return false; return -2;
} }
bool modify_username(char * old_uname, char * new_uname) { int modify_username(char * old_uname, char * new_uname) {
int idx = findUser(old_uname); int idx = findUser(old_uname);
if (idx == -1) if (idx == -1)
return false; return 0;
args->users[idx].name = realloc(args->users[idx].name, strlen(new_uname) + 1); int len = strlen(new_uname) + 1;
char * aux = realloc(args->users[idx].name, len);
if (aux == NULL)
return -1;
args->users[idx].name = aux;
strcpy(args->users[idx].name, new_uname); strcpy(args->users[idx].name, new_uname);
return true; args->users[idx].ulen = len;
return 1;
} }
bool modify_password(char * uname, char * new_pwd) { int modify_password(char * uname, char * new_pwd) {
int idx = findUser(uname); int idx = findUser(uname);
if (idx == -1) if (idx == -1)
return false; return 0;
args->users[idx].pass = realloc(args->users[idx].pass, strlen(new_pwd) + 1); char * aux = realloc(args->users[idx].pass, strlen(new_pwd) + 1);
if (aux == NULL)
return -1;
args->users[idx].pass = aux;
strcpy(args->users[idx].pass, new_pwd); strcpy(args->users[idx].pass, new_pwd);
return true; return 1;
} }
bool delete_user(char * uname) { bool delete_user(char * uname) {
@ -328,8 +475,38 @@ bool delete_user(char * uname) {
return false; return false;
free(args->users[idx].name); free(args->users[idx].name);
free(args->users[idx].pass); free(args->users[idx].pass);
for (int i = idx; i < args->nusers; i++) { for (unsigned int i = idx; i < args->nusers; i++) {
args->users[i] = args->users[i+1]; args->users[i] = args->users[i+1];
} }
args->nusers--;
return true;
}
size_t get_user_pages() {
return (args->nusers / PAGE_SIZE) + ((args->nusers % PAGE_SIZE != 0) ? 1 : 0);
}
bool get_users(char * buff, int page) {
size_t start = page * PAGE_SIZE, len = 0;
unsigned i = 0;
if (start >= args->nusers) {
return false;
}
i = start;
while (i < start + PAGE_SIZE && i < args->nusers) {
strcpy(buff + len, args->users[i].name);
len += args->users[i++].ulen;
buff[len - 1] = '\n';
}
if (i % PAGE_SIZE) {
buff[len] = '\n';
}
return true; return true;
} }
uint8_t verify_token(uint64_t token) {
return token == config_token;
}

View File

@ -24,10 +24,10 @@
#include "parser_utils.h" #include "parser_utils.h"
#define N(x) (sizeof(x)/sizeof((x)[0])) #define N(x) (sizeof(x)/sizeof((x)[0]))
#define BUFF_SIZE 4096 // TODO: decidir tamaño del buffer (2048 muy lento para archivos grandes!!!) #define BUFF_SIZE 4096
#define POP3_COMMAND_ARG 249 #define POP3_COMMAND_ARG 249
#define USER_MAX_SIZE 249
// TODO: hacer que cambie con nuestro proto
bool auth_active = true; bool auth_active = true;
bool pwd_dissector_active = false; bool pwd_dissector_active = false;
@ -56,6 +56,7 @@ enum socks_v5state {
DONE, DONE,
HELLO_ERROR, HELLO_ERROR,
AUTH_ERROR,
REQUEST_ERROR, REQUEST_ERROR,
ERROR, ERROR,
}; };
@ -108,6 +109,7 @@ struct auth_st {
/** buffer utilizado para I/O */ /** buffer utilizado para I/O */
buffer *rb, *wb; buffer *rb, *wb;
struct auth_parser parser; struct auth_parser parser;
char * username;
uint8_t verified; uint8_t verified;
}; };
@ -193,6 +195,7 @@ struct socks5 {
unsigned references; unsigned references;
bool parser; bool parser;
char * username;
struct socks5 * next; struct socks5 * next;
}; };
@ -236,6 +239,7 @@ static struct socks5 * socks5_new(int client_fd) {
stm_init(&ret->stm); stm_init(&ret->stm);
ret->parser = false; ret->parser = false;
ret->username = NULL;
buffer_init(&ret->read_buffer, N(ret->raw_buff_a), ret->raw_buff_a); buffer_init(&ret->read_buffer, N(ret->raw_buff_a), ret->raw_buff_a);
buffer_init(&ret->write_buffer, N(ret->raw_buff_b), ret->raw_buff_b); buffer_init(&ret->write_buffer, N(ret->raw_buff_b), ret->raw_buff_b);
@ -266,10 +270,13 @@ void parsers_destroy(struct socks5 * s) {
/** realmente destruye */ /** realmente destruye */
static void static void
socks5_destroy_(struct socks5 * s) { socks5_destroy_(struct socks5 * s) {
if(s->origin_resolution != NULL) { if (s->origin_resolution != NULL) {
freeaddrinfo(s->origin_resolution); freeaddrinfo(s->origin_resolution);
s->origin_resolution = 0; s->origin_resolution = 0;
} }
if (s->username != NULL) {
free(s->username);
}
free(s); free(s);
} }
@ -282,6 +289,13 @@ socks5_destroy(struct socks5 * s) {
if (s != NULL) { if (s != NULL) {
if (s->references == 1) { if (s->references == 1) {
parsers_destroy(s); parsers_destroy(s);
if (s->username != NULL) {
free(s->username);
}
if(s->origin_resolution != NULL) {
freeaddrinfo(s->origin_resolution);
s->origin_resolution = 0;
}
now_connect--; now_connect--;
if(pool_size < max_pool) { if(pool_size < max_pool) {
s->next = pool; s->next = pool;
@ -339,7 +353,7 @@ void socksv5_passive_accept(struct selector_key *key) {
goto fail; goto fail;
} }
state = socks5_new(client); state = socks5_new(client);
if(state == NULL) { if (state == NULL) {
// sin un estado, nos es imposible manejaro. // sin un estado, nos es imposible manejaro.
// tal vez deberiamos apagar accept() hasta que detectemos // tal vez deberiamos apagar accept() hasta que detectemos
// que se liberó alguna conexión. // que se liberó alguna conexión.
@ -432,8 +446,6 @@ static unsigned hello_read(struct selector_key * key) {
selector_set_interest_key(key, OP_WRITE); selector_set_interest_key(key, OP_WRITE);
} }
// return error ? ERROR : ret;
return ret; return ret;
} }
@ -505,8 +517,10 @@ static void on_auth_username(struct auth_parser * p, char * username) {
/** callback del parser utilizado en `read_auth' */ /** callback del parser utilizado en `read_auth' */
static void on_auth_password(struct auth_parser * p, char * password) { static void on_auth_password(struct auth_parser * p, char * password) {
uint8_t * verified = p->verified; uint8_t * verified = p->verified;
if (check_password(p->user_pos, password)) if (p->user_pos >= 0) {
* verified = 1; if (check_password(p->user_pos, password))
*verified = 1;
}
} }
/** inicializa las variables de los estados HELLO_… */ /** inicializa las variables de los estados HELLO_… */
@ -518,6 +532,9 @@ static void auth_read_init(const unsigned state, struct selector_key * key) {
d->parser.verified = &d->verified; d->parser.verified = &d->verified;
d->parser.on_username = on_auth_username; d->parser.on_username = on_auth_username;
d->parser.on_password = on_auth_password; d->parser.on_password = on_auth_password;
d->username = malloc(256);
ATTACHMENT(key)->username = d->username;
d->parser.username = d->username;
*d->parser.verified = 0; *d->parser.verified = 0;
d->parser.idx = 0; d->parser.idx = 0;
auth_parser_init(&d->parser); auth_parser_init(&d->parser);
@ -552,7 +569,12 @@ static unsigned auth_read(struct selector_key * key) {
ret = ERROR; ret = ERROR;
} }
return error ? ERROR : ret; if (error) {
ret = AUTH_ERROR;
selector_set_interest_key(key, OP_WRITE);
}
return ret;
} }
/** procesamiento del mensaje `auth' */ /** procesamiento del mensaje `auth' */
@ -564,6 +586,9 @@ static unsigned auth_process(const struct auth_st * d) {
if (auth_marshall(d->wb, (enum socks_response_status) r) == -1) { if (auth_marshall(d->wb, (enum socks_response_status) r) == -1) {
ret = ERROR; ret = ERROR;
} }
if (!v) {
ret = AUTH_ERROR;
}
return ret; return ret;
} }
@ -599,6 +624,10 @@ static unsigned auth_write(struct selector_key * key) {
return ret; return ret;
} }
static unsigned auth_write_error(struct selector_key * key) {
auth_write(key);
return ERROR;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// REQUEST // REQUEST
@ -651,7 +680,6 @@ static unsigned request_read(struct selector_key * key) {
selector_set_interest_key(key, OP_WRITE); selector_set_interest_key(key, OP_WRITE);
} }
// return error ? ERROR : ret;
return ret; return ret;
} }
@ -669,7 +697,6 @@ static unsigned request_process(struct selector_key * key, struct request_st * d
ATTACHMENT(key)->origin_domain = AF_INET; ATTACHMENT(key)->origin_domain = AF_INET;
d->request.dest_addr.ipv4.sin_port = d->request.dest_port; d->request.dest_addr.ipv4.sin_port = d->request.dest_port;
ATTACHMENT(key)->origin_addr_len = sizeof(d->request.dest_addr.ipv4); ATTACHMENT(key)->origin_addr_len = sizeof(d->request.dest_addr.ipv4);
// TODO: CAMBIAR, DA SUBDESBORDAMIENTO DE BÚFER :]
memcpy(&ATTACHMENT(key)->origin_addr, &d->request.dest_addr, sizeof(d->request.dest_addr.ipv4)); memcpy(&ATTACHMENT(key)->origin_addr, &d->request.dest_addr, sizeof(d->request.dest_addr.ipv4));
ret = request_connect(key, d); ret = request_connect(key, d);
break; break;
@ -677,20 +704,19 @@ static unsigned request_process(struct selector_key * key, struct request_st * d
ATTACHMENT(key)->origin_domain = AF_INET6; ATTACHMENT(key)->origin_domain = AF_INET6;
d->request.dest_addr.ipv6.sin6_port = d->request.dest_port; d->request.dest_addr.ipv6.sin6_port = d->request.dest_port;
ATTACHMENT(key)->origin_addr_len = sizeof(d->request.dest_addr.ipv6); ATTACHMENT(key)->origin_addr_len = sizeof(d->request.dest_addr.ipv6);
// TODO: CAMBIAR, DA SUBDESBORDAMIENTO DE BÚFER :]
memcpy(&ATTACHMENT(key)->origin_addr, &d->request.dest_addr, sizeof(d->request.dest_addr.ipv6)); memcpy(&ATTACHMENT(key)->origin_addr, &d->request.dest_addr, sizeof(d->request.dest_addr.ipv6));
ret = request_connect(key, d); ret = request_connect(key, d);
break; break;
} case socks_req_addr_domain: { } case socks_req_addr_domain: {
struct selector_key * k = malloc(sizeof(*key)); struct selector_key * k = malloc(sizeof(*key));
if (k == NULL) { if (k == NULL) {
ret = REQUEST_WRITE; ret = REQUEST_ERROR;
d->status = status_general_SOCKS_server_failure; d->status = status_general_SOCKS_server_failure;
selector_set_interest_key(key, OP_WRITE); selector_set_interest_key(key, OP_WRITE);
} else { } else {
memcpy(k, key, sizeof(*k)); memcpy(k, key, sizeof(*k));
if (-1 == pthread_create(&tid, 0, request_resolv_blocking, k)) { if (-1 == pthread_create(&tid, 0, request_resolv_blocking, k)) {
ret = REQUEST_WRITE; ret = REQUEST_ERROR;
d->status = status_general_SOCKS_server_failure; d->status = status_general_SOCKS_server_failure;
selector_set_interest_key(key, OP_WRITE); selector_set_interest_key(key, OP_WRITE);
} else { } else {
@ -740,13 +766,17 @@ static void * request_resolv_blocking(void * data) {
char buff[7]; char buff[7];
snprintf(buff, sizeof(buff), "%d", ntohs(s->client.request.request.dest_port)); snprintf(buff, sizeof(buff), "%d", ntohs(s->client.request.request.dest_port));
int ret = getaddrinfo(s->client.request.request.dest_addr.fqdn, buff, &hints, &s->origin_resolution); int ret = getaddrinfo(s->client.request.request.dest_addr.fqdn, buff, &hints, &s->origin_resolution);
if (ret != 0) { if (ret != 0) {
switch (ret) { switch (ret) {
case EAI_FAMILY: case EAI_FAMILY:
s->client.request.status = status_address_type_not_supported; s->client.request.status = status_address_type_not_supported;
break;
case EAI_FAIL: case EAI_FAIL:
s->client.request.status = status_host_unreachable; s->client.request.status = status_host_unreachable;
break;
default: default:
s->client.request.status = status_network_unreachable;
break; break;
} }
} }
@ -761,32 +791,16 @@ static unsigned request_resolv_done(struct selector_key * key) {
struct socks5 * s = ATTACHMENT(key); struct socks5 * s = ATTACHMENT(key);
unsigned int st = REQUEST_CONNECTING; unsigned int st = REQUEST_CONNECTING;
if (d->status == status_address_type_not_supported && d->status == status_host_unreachable) if (d->status == status_address_type_not_supported || d->status == status_host_unreachable || d->status == status_network_unreachable) {
return st; return request_connect(key, d);
}
if (s->origin_resolution == 0) { if (s->origin_resolution == 0) {
d->status = status_general_SOCKS_server_failure; d->status = status_general_SOCKS_server_failure;
} }
else {
struct addrinfo * addr = s->origin_resolution; s->origin_resolution_current = s->origin_resolution;
st = request_connect(key, d);
while (addr != NULL) {
s->origin_domain = addr->ai_family;
s->origin_addr_len = addr->ai_addrlen;
memcpy(&s->origin_addr, addr->ai_addr, addr->ai_addrlen);
st = request_connect(key, d);
if (d->status == status_succeeded) {
break;
}
else {
errno = 0;
}
addr = addr->ai_next;
}
freeaddrinfo(s->origin_resolution);
s->origin_resolution = 0;
}
return st; return st;
} }
@ -794,6 +808,13 @@ static unsigned request_connect(struct selector_key * key, struct request_st * d
bool error = false; bool error = false;
enum socks_response_status status = d->status; enum socks_response_status status = d->status;
int *fd = d->origin_fd; int *fd = d->origin_fd;
struct socks5 * s = ATTACHMENT(key);
if (s->origin_resolution_current != NULL) {
s->origin_domain = s->origin_resolution_current->ai_family;
s->origin_addr_len = s->origin_resolution_current->ai_addrlen;
memcpy(&s->origin_addr, s->origin_resolution_current->ai_addr, s->origin_resolution_current->ai_addrlen);
}
*fd = socket(ATTACHMENT(key)->origin_domain, SOCK_STREAM, 0); *fd = socket(ATTACHMENT(key)->origin_domain, SOCK_STREAM, 0);
if (*fd == -1) { if (*fd == -1) {
@ -819,9 +840,11 @@ static unsigned request_connect(struct selector_key * key, struct request_st * d
} }
ATTACHMENT(key)->references += 1; ATTACHMENT(key)->references += 1;
} else { } else {
status = errno_to_socks(errno); if (s->origin_resolution_current == NULL || s->origin_resolution_current->ai_next == NULL) {
error = true; status = errno_to_socks(errno);
goto finally; error = true;
goto finally;
}
} }
} else { } else {
abort(); abort();
@ -833,6 +856,10 @@ finally:
close(*fd); close(*fd);
*fd = -1; *fd = -1;
} }
request_marshall(d->wb, d->status);
selector_set_interest_key(key, OP_WRITE);
return REQUEST_ERROR;
} }
d->status = status; d->status = status;
@ -854,19 +881,21 @@ static void request_connecting_init(const unsigned state, struct selector_key *k
} }
static unsigned request_connecting(struct selector_key * key) { static unsigned request_connecting(struct selector_key * key) {
int error; int error = 0;
socklen_t len = sizeof(error); socklen_t len = sizeof(error);
struct connecting * d = &ATTACHMENT(key)->orig.conn; struct connecting * d = &ATTACHMENT(key)->orig.conn;
struct request_st * req = &ATTACHMENT(key)->client.request;
struct socks5 * sx = ATTACHMENT(key);
if (getsockopt(key->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { if (getsockopt(key->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error) {
*d->status = status_general_SOCKS_server_failure; if (sx->origin_resolution_current != NULL && sx->origin_resolution_current->ai_next != NULL) {
} else { sx->origin_resolution_current = sx->origin_resolution_current->ai_next;
if (error == 0) { return request_connect(key, req);
*d->status = status_succeeded;
*d->origin_fd = key->fd;
} else {
*d->status = errno_to_socks(error);
} }
*d->status = errno_to_socks(error);
} else {
*d->status = status_succeeded;
*d->origin_fd = key->fd;
} }
if (-1 == request_marshall(d->wb, *d->status)) { if (-1 == request_marshall(d->wb, *d->status)) {
@ -879,23 +908,77 @@ static unsigned request_connecting(struct selector_key * key) {
return SELECTOR_SUCCESS == s ? REQUEST_WRITE : ERROR; return SELECTOR_SUCCESS == s ? REQUEST_WRITE : ERROR;
} }
void log_request(enum socks_response_status status, const struct sockaddr * client_addr, const struct sockaddr * origin_addr) { void log_request_access(enum socks_response_status status, const struct sockaddr * client_addr, const struct sockaddr * origin_addr, char * username) {
char cbuff[SOCKADDR_TO_HUMAN_MIN * 2 + 2 + 32] = {0}; char cbuff[SOCKADDR_TO_HUMAN_MIN * 2 + 2 + 32] = {0};
unsigned n = N(cbuff); unsigned n = N(cbuff);
time_t now = 0; time_t now = 0;
time(&now); time(&now);
strftime(cbuff, n, "%FT%TZ\t", gmtime(&now)); strftime(cbuff, n, "%FT%TZ ", gmtime(&now));
size_t len = strlen(cbuff); size_t len = strlen(cbuff);
sockaddr_to_human(cbuff + len, N(cbuff) - len, client_addr); sockaddr_to_human(cbuff + len, N(cbuff) - len, client_addr);
strncat(cbuff, "\t", n - 1); strncat(cbuff, " ", n - 1);
cbuff[n - 1] = 0; cbuff[n - 1] = 0;
len = strlen(cbuff); len = strlen(cbuff);
sockaddr_to_human(cbuff + len, N(cbuff) - len, origin_addr); sockaddr_to_human(cbuff + len, N(cbuff) - len, origin_addr);
fprintf(stdout, "%s\tstatus=%d\n", cbuff, status); if (username != NULL) {
fprintf(stdout, "register=A user=%s %s status=%d\n", username, cbuff, status);
} else {
fprintf(stdout, "register=A anon %s status=%d\n", cbuff, status);
}
FILE * file = fopen("access.log", "a"); FILE * file = fopen("access.log", "a");
fprintf(file, "%s\tstatus=%d\n", cbuff, status); if (file == NULL)
return;
if (username != NULL) {
fprintf(file, "register=A user=%s %s status=%d\n", username, cbuff, status);
} else {
fprintf(file, "register=A %s status=%d\n", cbuff, status);
}
fclose(file);
}
void log_request_password(const struct sockaddr * origin_addr, char * username, char * diss_name, char * diss_pass) {
char cbuff[SOCKADDR_TO_HUMAN_MIN * 2 + 2 + 32] = {0};
unsigned n = N(cbuff);
time_t now = 0;
time(&now);
strftime(cbuff, n, "%FT%TZ ", gmtime(&now));
size_t len = strlen(cbuff);
sockaddr_to_human(cbuff + len, N(cbuff) - len, origin_addr);
in_port_t port = 0;
switch(origin_addr->sa_family) {
case AF_INET:
port = ((struct sockaddr_in *) origin_addr)->sin_port;
break;
case AF_INET6:
port = ((struct sockaddr_in6 *) origin_addr)->sin6_port;
break;
}
char * protocol;
if (port == 110) {
protocol = "POP3";
}
else {
protocol = "UNK(POP3)";
}
if (username != NULL) {
fprintf(stdout, "register=P user=%s %s protocol=%s diss_user=%s diss_pass=%s\n", username, cbuff, protocol, diss_name, diss_pass);
} else {
fprintf(stdout, "register=P anon %s protocol=%s diss_user=%s diss_pass=%s\n", cbuff, protocol, diss_name, diss_pass);
}
FILE * file = fopen("passwords.log", "a");
if (file == NULL)
return;
if (username != NULL) {
fprintf(file, "register=P user=%s %s protocol=%s diss_user=%s diss_pass=%s\n", username, cbuff, protocol, diss_name, diss_pass);
} else {
fprintf(file, "register=P anon %s protocol=%s diss_user=%s diss_pass=%s\n", cbuff, protocol, diss_name, diss_pass);
}
fclose(file); fclose(file);
} }
@ -930,7 +1013,7 @@ static unsigned request_write(struct selector_key * key) {
} }
} }
log_request(d->status, (const struct sockaddr *) &ATTACHMENT(key)->client_addr, (const struct sockaddr *) &ATTACHMENT(key)->origin_addr); log_request_access(d->status, (const struct sockaddr *) &ATTACHMENT(key)->client_addr, (const struct sockaddr *) &ATTACHMENT(key)->origin_addr, ATTACHMENT(key)->username);
return ret; return ret;
} }
@ -948,20 +1031,19 @@ static void copy_init(const unsigned state, struct selector_key * key) {
d->duplex = OP_READ | OP_WRITE; d->duplex = OP_READ | OP_WRITE;
d->other = &ATTACHMENT(key)->orig.copy; d->other = &ATTACHMENT(key)->orig.copy;
// struct parser_definition * user = parser_utils_strcmpi("user"); if (pwd_dissector_active) {
// d->parser_user = parser_init(parser_no_classes(), user); d->user_done = false;
// struct parser_definition * pass = parser_utils_strcmpi("pass"); d->pass_done = false;
// d->parser_pass = parser_init(parser_no_classes(), pass); d->parser_user = parser_init(parser_no_classes(), user);
// d->user = malloc(249); d->parser_pass = parser_init(parser_no_classes(), pass);
// d->pass = malloc(249); d->user = malloc(USER_MAX_SIZE);
d->user_done = false; d->pass = malloc(USER_MAX_SIZE);
d->pass_done = false; ATTACHMENT(key)->parser = true;
d->parser_user = parser_init(parser_no_classes(), user); }
d->parser_pass = parser_init(parser_no_classes(), pass); else {
d->user = malloc(249); d->parser_user = NULL;
d->pass = malloc(249); d->parser_pass = NULL;
}
ATTACHMENT(key)->parser = true;
d = &ATTACHMENT(key)->orig.copy; d = &ATTACHMENT(key)->orig.copy;
d->fd = &ATTACHMENT(key)->origin_fd; d->fd = &ATTACHMENT(key)->origin_fd;
@ -1046,12 +1128,7 @@ static unsigned copy_r(struct selector_key * key) {
if (*(ptr + i) == '\n') { if (*(ptr + i) == '\n') {
d->pass_done = true; d->pass_done = true;
d->pass[k - 1] = 0; d->pass[k - 1] = 0;
char buff[SOCKADDR_TO_HUMAN_MIN + 2] = {0}; log_request_password((const struct sockaddr *) &ATTACHMENT(key)->origin_addr, ATTACHMENT(key)->username, d->user, d->pass);
sockaddr_to_human(buff, N(buff), (struct sockaddr *) &ATTACHMENT(key)->origin_addr);
fprintf(stdout, "%s -> USER: %s - PASS: %s\n", buff, d->user, d->pass);
FILE * file = fopen("passwords.log", "a");
fprintf(file, "%s -> USER: %s - PASS: %s\n", buff, d->user, d->pass);
fclose(file);
d->user_done = false; d->user_done = false;
d->pass_done = false; d->pass_done = false;
parser_reset(d->parser_user); parser_reset(d->parser_user);
@ -1148,6 +1225,9 @@ static const struct state_definition client_statbl[] = {
.state = HELLO_ERROR, .state = HELLO_ERROR,
.on_write_ready = hello_write_error, .on_write_ready = hello_write_error,
}, { }, {
.state = AUTH_ERROR,
.on_write_ready = auth_write_error,
}, {
.state = REQUEST_ERROR, .state = REQUEST_ERROR,
.on_write_ready = request_write_error, .on_write_ready = request_write_error,
}, { }, {