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=200112L
LDFLAGS = -lpthread -lm
LDFLAGS = -lpthread
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
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=
CLIENT_SOURCES=src/client.c src/netutils.c
SERVER_OBJECTS=$(SERVER_SOURCES:.c=.o)
CLIENT_OBJECTS=$(CLIENT_SOURCES:.c=.o)
SERVER_TARGET=socks5d
@ -15,7 +11,7 @@ CLIENT_TARGET=client
all: $(SERVER_OBJECTS) $(SERVER_TARGET) $(CLIENT_OBJECTS) $(CLIENT_TARGET)
%.o : %.c
$(CC) $(CCFLAGS) $(LDFLAGS) -I ./include -c $< -o $@
$(CC) $(CCFLAGS) -I ./include -c $< -o $@
$(SERVER_TARGET): $(SERVER_OBJECTS)
$(CC) $(CCFLAGS) $(LDFLAGS) -I ./include -o $@ $^

View File

@ -23,16 +23,52 @@ make all
## 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
./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
```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>
@ -46,29 +82,18 @@ make test
Por último, si quiere hacer un análisis dinámico (usando [valgrind](https://valgrind.org/)) puede hacerlo mediante:
```bash
valgrind ./server
```
y en otra terminal
```bash
valgrind ./client
valgrind ./socks5d
```
## 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
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
- Barmasch, Juan Martín (61033)
- Bellver, Ezequiel (61268)
- Lo Coco, Santiago (61301)
### Bottler:
- Barmasch, Juan Martín (61033)
- Bellver, Ezequiel (61268)
- Lo Coco, Santiago (61301)

View File

@ -1,4 +1,4 @@
Bottler Protocol version 1
Bottler Configuration Protocol version 1
1. Introduction
@ -9,13 +9,12 @@ Note:
Unless otherwise noted, the decimal numbers appearing in packet -
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
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
associated (one or two octet) length field, or by a data type field.
NETWORK ORDER!!!
associated (one or two octet) length field.
Fields taking more than one octet are in network octet order.
2. Requests
@ -29,45 +28,33 @@ Note:
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
CMD field describes the command that will be run. The
PARAMETERS field describes the parameters that will be passed
depending on the CMD field value.
CMD field describes the command that will be run. The PARAMETERS
field describes the parameters that will be passed depending on the
CMD field value.
The values currently defined for CMD are:
o X'00' GET METRICS
o X'01' GET BUFFER SIZE
o X'02' SET BUFFER SIZE
o X'03' GET TIMEOUT VALUE
o X'04' SET TIMEOUT VALUE
o X'05' GET USER PAGES
o X'06' LIST USERS
o X'07' GET USER LAST CONNECTION
o X'08' MODIFY USERNAME
o X'09' MODIFY PASSWORD
o X'0A' ADD USER
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
o X'01' GET USER PAGES
o X'02' LIST USERS
o X'03' MODIFY USERNAME
o X'04' MODIFY PASSWORD
o X'05' ADD USER
o X'06' DELETE USER
o X'07' GET PASSWORD DISSECTOR STATUS
o X'08' SET PASSWORD DISSECTOR
o X'09' GET PROXY AUTHENTICATION STATUS
o X'0A' SET PROXY AUTHENTICATION
TODO: metodo para saber cuanto tiene una página? o lo hardcodeamos en el proto?
TODO: unknown command 0xFE
TODO: get users de ettercap (not quite)
3. Commands
2. Commands
3.1. CMD: X'00' - GET METRICS
CMD: X'00' - GET METRICS
Requests historical metrics values. Which are hostorical
connections, current connections and total bytes transmited.
Connections are represented as an unisgned int taking 4 bytes
Total bytes transmited as a unsigned long taking 8 bytes.
Requests historical metrics values. Which are historical
connections, current connections and total bytes transmitted.
Connections are represented as an unsigned int taking 4 bytes
Total bytes transmitted as an unsigned long taking 8 bytes.
Request:
+-------+-------+---------+
@ -86,137 +73,23 @@ CMD: X'00' - GET METRICS
The possible values for CODE are:
o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN
o X'D0' VERSION NOT SUPPORTED
o X'FF' METHOD NOT SUPPORTED
CMD: X'01' - GET BUFFER SIZE
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
3.2. CMD: X'01' - GET USER PAGES
Requests amount of pages of valid users for the proxy SOCKS
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:
+-------+-------+---------+
| VER | TOKEN | CMD |
+-------+-------+---------+
| X'01' | 8 | X'05' |
| X'01' | 8 | X'01' |
+-------+-------+---------+
Response:
@ -229,49 +102,59 @@ CMD: X'05' - GET USER PAGES
The possible values for CODE are:
o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN
o X'D0' VERSION 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
server.
Response comes as an integers taking 2 bytes. (representing)
Requests an user page containing usernames of valid users for
the proxy SOCKS server for a given page number.
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:
+-------+-------+---------+--------+
| VER | TOKEN | CMD | PAGE |
+-------+-------+---------+--------+
| X'01' | 8 | X'06' | 2 |
| X'01' | 8 | X'02' | 2 |
+-------+-------+---------+--------+
Response:
+-------+--------+---------------+
| VER | CODE | PAGE |
| VER | CODE | PAGE SIZE |
+-------+--------+---------------+
| X'01' | 1 | Page size |
+-------+--------+---------------+
PAGE represents a page number greater or equal to 1.
The possible values for CODE are:
o X'00' OK
o X'A0' SERVER ERROR
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'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.
Response comes as with a code representing the output of
Response comes with a code representing the output of
the action.
Request:
+-------+-------+---------+--------+-----------+---------+----------+
| 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:
@ -282,31 +165,39 @@ CMD: X'08' - MODIFY USERNAME
+-------+--------+
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
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:
o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN
o X'C0' INVALID PARAMETER VALUE
o X'C1' USER NOT FOUND
o X'C1' USER ALREADY EXISTS
o X'D0' VERSION 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
UNAME.
Response comes as with a code representing the output of
Response comes 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 |
| X'01' | 8 | X'04' | 1 | 1 to 255 | 1 | 1 to 255 |
+-------+-------+---------+--------+-----------+-------+----------+
Response:
@ -318,30 +209,37 @@ CMD: X'09' - MODIFY PASSWORD
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
password of the user with the username UNAME. ULEN
describes the 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:
o X'00' OK
o X'A0' SERVER ERROR
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
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.
Response comes as with a code representing the output of
Response comes 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 |
| X'01' | 8 | X'05' | 1 | 1 to 255 | 1 | 1 to 255 |
+-------+-------+---------+--------+-----------+-------+----------+
Response:
@ -356,26 +254,34 @@ CMD: X'0A' - ADD USER
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.
Both UNAME and PASS must only contain printable ASCII
characters other than ':'.
The possible values for CODE are:
o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN
o X'C0' INVALID PARAMETER VALUE
o X'C2' USER ALREADY EXISTS
o X'D0' VERSION 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.
Response comes as with a code representing the output of
Response comes with a code representing the output of
the action.
Request:
+-------+-------+---------+--------+-----------+
| VER | TOKEN | CMD | ULEN | UNAME |
+-------+-------+---------+--------+-----------+
| X'01' | 8 | X'0B' | 1 | 1 to 255 |
| X'01' | 8 | X'06' | 1 | 1 to 255 |
+-------+-------+---------+--------+-----------+
Response:
@ -388,21 +294,28 @@ CMD: X'0B' - DELETE USER
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.
UNAME must only contain printable ASCII
characters other than ':'.
The possible values for CODE are:
o X'00' OK
o X'A0' SERVER ERROR
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
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
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
password dissector.
@ -410,7 +323,7 @@ CMD: X'0C' - GET PASSWORD DISSECTOR STATUS
+-------+-------+---------+
| VER | TOKEN | CMD |
+-------+-------+---------+
| X'01' | 8 | X'0C' |
| X'01' | 8 | X'07' |
+-------+-------+---------+
Response:
@ -422,28 +335,29 @@ CMD: X'0C' - GET PASSWORD DISSECTOR STATUS
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.
service is down. Any other value greater than 0 represents
password dissector being active.
The possible values for CODE are:
o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN
o X'D0' VERSION 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
the proxy server.
Response comes as with a code representing the output of
Response comes with a code representing the output of
the action.
Request:
+-------+-------+---------+--------+
| VER | TOKEN | CMD | STATUS |
+-------+-------+---------+--------+
| X'01' | 8 | X'0D' | 1 |
| X'01' | 8 | X'08' | 1 |
+-------+-------+---------+--------+
Response:
@ -455,23 +369,24 @@ CMD: X'0D' - SET PASSWORD DISSECTOR STATUS
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
service will be turned off. Any other value greater than 0
represents 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'A0' SERVER ERROR
o X'B0' INVALID TOKEN
o X'D0' VERSION 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
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
authentication service.
@ -479,7 +394,7 @@ CMD: X'0E' - GET PROXY AUTHENTICATION STATUS
+-------+-------+---------+
| VER | TOKEN | CMD |
+-------+-------+---------+
| X'01' | 8 | X'0E' |
| X'01' | 8 | X'09' |
+-------+-------+---------+
Response:
@ -491,28 +406,29 @@ CMD: X'0E' - GET PROXY AUTHENTICATION STATUS
STATUS represents the status of the authentication
service. If STATUS is X'00' then authentication service
is down. Any other value representes authentication
being active.
is down. Any other value greater than 0 represents
authentication being active.
The possible values for CODE are:
o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN
o X'D0' VERSION 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
proxy server.
Response comes as with a code representing the output of
Response comes with a code representing the output of
the action.
Request:
+-------+-------+---------+--------+
| VER | TOKEN | CMD | STATUS |
+-------+-------+---------+--------+
| X'01' | 8 | X'0F' | 1 |
| X'01' | 8 | X'0A' | 1 |
+-------+-------+---------+--------+
Response:
@ -522,332 +438,37 @@ CMD: X'0F' - SET PROXY AUTHENTICATION STATUS
| 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
service. If STATUS is X'00' then authentication service
is down. Any other value representes authentication
being active.
service. If STATUS is X'00' then authentication
service will be turned off. Any other value greater
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:
o X'00' OK
o X'A0' SERVER ERROR
o X'B0' INVALID TOKEN
o X'D0' VERSION 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
proxy server.
Response comes as with a code representing the output of
the action.
If an invalid CMD is requested to a server, it must
respond with a package such as:
Request:
+-------+-------+---------+--------+
| VER | TOKEN | CMD | STATUS |
+-------+-------+---------+--------+
| X'01' | 8 | X'0F' | 1 |
+-------+-------+---------+--------+
Response:
+-------+--------+
| VER | CODE |
+-------+--------+
| X'01' | 1 |
| X'01' | X'FE' |
+-------+--------+
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.
Where the CODE X'FE' means that the command is unknown.
The possible values for CODE are:
5. Authors
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
Barmasch, Juan Martín (61033)
Bellver, Ezequiel (61268)
Lo Coco, Santiago (61301)

View File

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

View File

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

View File

@ -13,6 +13,7 @@ enum auth_state {
auth_passwd,
auth_done,
auth_error_unsupported_version,
auth_user_error
};
struct auth_parser {
@ -21,7 +22,7 @@ struct auth_parser {
void * data;
enum auth_state state;
int user_pos;
char username[255];
char * username;
char idx;
char password[255];
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);
extern int auth_marshall(buffer * b, uint8_t method);
extern int auth_marshall(buffer * b, uint8_t status);
#endif

View File

@ -2,7 +2,7 @@
#define BUFFER_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

View File

@ -2,29 +2,25 @@
#define CLIENT_H
#define CMD_GET_METRICS 0x00
#define CMD_GET_BUFFER_SIZE 0x01
#define CMD_SET_BUFFER_SIZE 0x02
#define CMD_GET_TIMEOUT 0x03
#define CMD_SET_TIMEOUT 0x04
#define CMD_GET_USER_PAGES 0x05
#define CMD_LIST_USERS 0x06
#define CMD_GET_USER_LAST_CONNECTION 0x07
#define CMD_MODIFY_USERNAME 0x08
#define CMD_MODIFY_PASSWORD 0x09
#define CMD_ADD_USER 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_GET_USER_PAGES 0x01
#define CMD_LIST_USERS 0x02
#define CMD_MODIFY_USERNAME 0x03
#define CMD_MODIFY_PASSWORD 0x04
#define CMD_ADD_USER 0x05
#define CMD_DELETE_USER 0x06
#define CMD_GET_PASSWORD_DISSECTOR_STATUS 0x07
#define CMD_MODIFY_PASSWORD_DISSECTOR_STATUS 0x08
#define CMD_GET_AUTHENTICATION_STATUS 0x09
#define CMD_MODIFY_AUTHENTICATION_STATUS 0x0A
#define RESPONSE_OK 0x00
#define RESPONSE_SERVER_ERROR 0xA0
#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_UNKNOWN_COMMAND 0xFE
#define RESPONSE_CMD_NOT_SUPPORTED 0xFF
#endif

View File

@ -8,27 +8,28 @@
#define STR_SIZE 255
#define CMD_GET_METRICS 0x00
#define CMD_GET_BUFFER_SIZE 0x01
#define CMD_SET_BUFFER_SIZE 0x02
#define CMD_GET_TIMEOUT 0x03
#define CMD_SET_TIMEOUT 0x04
#define CMD_GET_USER_PAGES 0x05
#define CMD_LIST_USERS 0x06
#define CMD_GET_USER_LAST_CONNECTION 0x07
#define CMD_MODIFY_USERNAME 0x08
#define CMD_MODIFY_PASSWORD 0x09
#define CMD_ADD_USER 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_GET_USER_PAGES 0x01
#define CMD_LIST_USERS 0x02
#define CMD_MODIFY_USERNAME 0x03
#define CMD_MODIFY_PASSWORD 0x04
#define CMD_ADD_USER 0x05
#define CMD_DELETE_USER 0x006
#define CMD_GET_PASSWORD_DISSECTOR_STATUS 0x07
#define CMD_MODIFY_PASSWORD_DISSECTOR_STATUS 0x08
#define CMD_GET_AUTHENTICATION_STATUS 0x09
#define CMD_MODIFY_AUTHENTICATION_STATUS 0x0A
#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 {
cmd_version,
cmd_token,
@ -38,6 +39,7 @@ enum cmd_state {
cmd_error_unsupported_version,
cmd_error_invalid_token,
cmd_error_unsupported_command,
cmd_error_invalid_parameter
};
enum param_state {
@ -78,6 +80,8 @@ struct cmd_parser {
void * parameters;
};
extern bool is_valid(uint8_t c);
void cmd_parser_init(struct cmd_parser * p);
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);
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);
//extern int cmd_marshall(buffer * b, uint8_t method);
#endif

View File

@ -4,7 +4,7 @@
#include "stm.h"
#include "cmd.h"
#define BUFF_SIZE 1024
#define BUFF_SIZE 4096
struct cmd_st {
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 cmd_resolve(struct request * request, struct sockaddr ** originaddr, socklen_t * origin_len, int * domain);
#endif

View File

@ -1,12 +1,18 @@
#ifndef SERVER_H
#define SERVER_H
#define PAGE_SIZE 5
#define USERNAME_MAX_LEN 256
int findUser(char * username);
int check_password(int idx, char * password);
bool add_user(char * username, char * password);
bool modify_username(char * old_uname, char * new_uname);
bool modify_password(char * uname, char * new_pwd);
int add_user(char * username, char * password);
int modify_username(char * old_uname, char * new_uname);
int modify_password(char * uname, char * new_pwd);
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

View File

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

View File

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

View File

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

View File

@ -14,348 +14,518 @@
#include <netinet/tcp.h>
#include <fcntl.h>
#include <getopt.h>
#include <arpa/inet.h>
#include <netutils.h>
#include "client.h"
#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]))
static void version(void) {
fprintf(stderr, "BProxy v1.0\nITBA Protocolos de Comunicación 2021/1 -- Grupo 7\nVer LICENSE.md\n");
static unsigned short get_port(const char *s) {
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) {
fprintf(stderr,
"Usage: %s [token] [OPTION]\n\n"
" -h Imprime la ayuda y termina.\n"
" -m Obtener métricas del servidor.\n"
" -b Obtener el tamaño del buffer.\n"
" -B <value> Modificar el tamaño del buffer.\n"
" -t Obtener el valor del timeout.\n"
" -T <value> Modificar el valor del timeout.\n"
" -f Obtener cantidad de páginas de nombres de usuario.\n"
" -u <page> Obtener nombres de usuario de la página especificada.\n"
" -l <name> Obtener la última conexión del usuario específicado.\n"
" -c <name>:<new_name> Nombre de usuario y nuevo nombre de usuario\n"
" -p <name>:<new_pass> Nombre de usuario y su nueva contraseña\n"
" -n <name>:<pass> Nombre de usuario y contraseña del usuario que desea ser agregado\n"
" -d <name> Nombre del usuario que desea ser borrado\n"
" -s Obtener el estado del disector de contraseñas POP3.\n"
" -S <estado> Modificar el estado del disector de contraseñas POP3.\n"
" -a Obtener el estado de la autorización del proxy.\n"
" -A <estado> Modificar el estado de la autorización del proxy.\n"
" -z Obtener el estado del servidor proxy.\n"
" -Z <estado> Modificar el estado del servidor proxy.\n"
" -r Reinicia el servidor\n\n",
static void version(void) {
fprintf(stdout, "BProxy v1.0\nITBA Protocolos de Comunicación 2021/1 -- Group 7\nSee LICENSE.md\n");
}
static void usage(const char * progname) {
fprintf(stdout,
"Usage: %s [OPTION]\n\n"
" -h Prints help\n"
" -v Prints client version\n"
" [TOKEN] -m Get server metrics\n"
" [TOKEN] -f Get amount of user pages\n"
" [TOKEN] -u <page> Get users in a page\n"
" [TOKEN] -c <name>:<new_name> Change username from <name> to <new_name>\n"
" [TOKEN] -p <name>:<new_pass> Change user' with username <name> password\n"
" [TOKEN] -n <name>:<pass> Adds user to proxy server\n"
" [TOKEN] -d <name> Deletes user from proxy server\n"
" [TOKEN] -s Get password dissector status\n"
" [TOKEN] -S <state> Modify password dissector status\n"
" [TOKEN] -a Get proxy authentication status\n"
" [TOKEN] -L <conf addr> Address of management service.\n"
" [TOKEN] -P <conf port> Port of management service.\n"
" [TOKEN] -A <state> Modify proxy authentication status\n"
"Where TOKEN is an 8-byte unsigned integer\n\n",
progname);
exit(1);
}
// aceptar -L
uint8_t parse_args(int argc, char ** argv, uint8_t * buffer) {
uint8_t parse_args(int argc, char ** argv, uint8_t * buffer, char ** address, unsigned short * port) {
int c;
if (argc <= 1 || argv[1][0] == '-') {
fprintf(stderr, "You must enter a valid token.\n");
if (argc <= 1) {
fprintf(stderr, "You must enter a valid token\n");
exit(EXIT_FAILURE);
}
uint64_t token = atol(argv[1]);
bool sent_token = false;
buffer[0] = 0x01;
if (argv[1][0] != '-') {
uint64_t token = atol(argv[1]);
buffer[1] = token>>56;
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;
buffer[0] = 0x01;
for (int i = 1; i < argc; ++i) {
argv[i] = argv[i+1];
}
argc--;
buffer[1] = token>>56;
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;
c = getopt(argc, argv, "hmbtfsazrB:T:l:u:c:A:S:p:n:d:Z:");
// retorna : o ? si le falta el argumento
if (c == -1) {
fprintf(stderr, "One option required\n");
exit(EXIT_FAILURE); // TODO: chequear bien
return 0xFF;
for (int i = 1; i < argc; ++i) {
argv[i] = argv[i+1];
}
argc--;
sent_token = true;
}
if (optind < 3 && argc > 2) {
fprintf(stderr, "Only one option allowed\n");
exit(EXIT_FAILURE);
}
char args = 0;
bool Lpresent = false, Ppresent = false;
while (args < 3) {
if (args == 1) {
if (!(Lpresent || Ppresent))
break;
}
if (args == 2) {
if (!(Lpresent && Ppresent))
break;
}
uint16_t value;
uint8_t ulen, plen, nulen;
char * p;
switch (c) {
case 'h':
usage(argv[0]);
break;
case 'm':
buffer[9] = 0x00;
break;
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);
c = getopt(argc, argv, "hvmfu:c:p:n:d:sS:aA:L:P:");
if (c == -1) {
fprintf(stderr, "A valid option is required\n");
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];
}
void parse_response(uint8_t * buffer, uint8_t cmd) {
int parse_response(uint8_t * buffer, uint8_t cmd) {
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;
uint64_t bytes = 0;
uint16_t pages, k = 0, users = 0;
switch (buffer[1]) {
case RESPONSE_OK:
fprintf(stdout, "Success.\n");
switch (cmd) {
case CMD_GET_METRICS:
fprintf(stdout, "Metrics:\n");
total_conn += buffer[2];
total_conn <<= 24;
total_conn <<= 8;
total_conn += buffer[3];
total_conn <<= 16;
total_conn <<= 8;
total_conn += buffer[4];
total_conn <<= 8;
total_conn += buffer[5];
now_conn += buffer[6];
now_conn <<= 24;
now_conn <<= 8;
now_conn += buffer[7];
now_conn <<= 16;
now_conn <<= 8;
now_conn += buffer[8];
now_conn <<= 8;
now_conn += buffer[9];
bytes += buffer[10];
bytes <<= 56;
bytes <<= 8;
bytes += buffer[11];
bytes <<= 48;
bytes <<= 8;
bytes += buffer[12];
bytes <<= 40;
bytes <<= 8;
bytes += buffer[13];
bytes <<= 32;
bytes <<= 8;
bytes += buffer[14];
bytes <<= 24;
bytes <<= 8;
bytes += buffer[15];
bytes <<= 16;
bytes <<= 8;
bytes += buffer[16];
bytes <<= 8;
bytes += buffer[17];
fprintf(stdout, "\tTotal connections: %u\n\tCurrent connections: %u\n\tTotal bytes transferred: %lu\n", total_conn, now_conn, bytes);
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:
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;
case CMD_LIST_USERS:
fprintf(stdout, "Users... \n");
break;
case CMD_GET_USER_LAST_CONNECTION:
fprintf(stdout, "Users... \n");
fprintf(stdout, "Users:\n");
while (users < PAGE_SIZE && !(k > 2 && buffer[k - 1] == '\n' && buffer[k] == '\n')) {
if (buffer[k] == '\n')
users++;
putchar(buffer[k++]);
}
break;
case CMD_GET_PASSWORD_DISSECTOR_STATUS:
fprintf(stdout, "Password dissector status: %s\n", buffer[2] ? "ON" : "OFF");
break;
case CMD_MODIFY_PASSWORD_DISSECTOR_STATUS:
break;
case CMD_GET_AUTHENTICATION_STATUS:
fprintf(stdout, "Proxy authentication status: %s\n", buffer[2] ? "ON" : "OFF");
break;
case CMD_MODIFY_PASSWORD_DISSECTOR_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_PASSWORD:
case CMD_ADD_USER:
case CMD_DELETE_USER:
case CMD_CHANGE_PROXY_SERVER_STATUS:
case CMD_RESTART_PROXY_SERVER:
fprintf(stdout, "Success\n");
break;
default:
break;
}
return EXIT_SUCCESS;
case RESPONSE_SERVER_ERROR:
fprintf(stderr, "ERROR - Server error\n");
break;
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;
case RESPONSE_CMD_NOT_SUPPORTED:
fprintf(stdout, "Command not supported.\n");
fprintf(stderr, "ERROR - Command not supported\n");
break;
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;
default:
fprintf(stderr, "ERROR - Unknown response status\n");
break;
}
return EXIT_FAILURE;
}
int main(int argc, char **argv) {
const char *err_msg = NULL;
uint8_t * recv_buffer = NULL;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(8080);
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;
const int client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
unsigned char buf[sizeof(struct in6_addr)];
int domain = AF_INET;
if (address != NULL) {
if (inet_pton(AF_INET6, address, buf)) {
domain = AF_INET6;
} else if (!inet_pton(AF_INET, address, buf)) {
err_msg = "Incorrect network address";
goto finally;
}
}
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) {
err_msg = "Unable to create UDP socket";
goto finally;
}
if (connect(client, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
err_msg = "Unable to connect to UDP socket";
goto finally;
char buff[SOCKADDR_TO_HUMAN_MIN + 1];
if (domain == AF_INET) {
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};
uint8_t cmd = parse_args(argc, argv, buffer);
ssize_t sent = sendto(client, buffer, N(buffer), 0, NULL, sizeof(addr));
if (sent < 0) {
err_msg = "Unable to send cmd";
ssize_t sent;
if (domain == AF_INET) {
sent = sendto(client, buffer, N(buffer), 0, NULL, sizeof(addr_ipv4));
if (sent < 0) {
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;
}
uint8_t * recv_buffer = calloc(1, MAX_RECV_SIZE);
ssize_t received = recvfrom(client, recv_buffer, MAX_RECV_SIZE, 0, NULL, NULL);
if (received < 0) {
err_msg = "Unable to receive cmd";
goto finally;
}
parse_response(recv_buffer, cmd);
int ret = parse_response(recv_buffer, cmd);
err_msg = NULL;
int ret = EXIT_SUCCESS;
finally:
free(recv_buffer);
if (recv_buffer != NULL) {
free(recv_buffer);
}
if (err_msg) {
perror(err_msg);
ret = EXIT_FAILURE;

View File

@ -2,7 +2,6 @@
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <stdio.h>
#include <stdlib.h>
#include <math.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) {
case param_ulen:
p->remaining = b;
if (p->remaining == 0)
p->state = cmd_error_invalid_parameter;
p->param_state = param_uname;
break;
case param_uname:
if (!is_valid(b)) {
p->state = cmd_error_invalid_parameter;
break;
}
*(p->username + p->idx++) = (char) b;
p->remaining--;
if (p->remaining == 0) {
*(p->username + 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;
else if (*p->cmd == CMD_MODIFY_USERNAME)
p->param_state = param_new_ulen;
@ -59,9 +64,15 @@ enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b) {
break;
case param_plen:
p->remaining = b;
if (p->remaining == 0)
p->state = cmd_error_invalid_parameter;
p->param_state = param_passwd;
break;
case param_passwd:
if (!is_valid(b)) {
p->state = cmd_error_invalid_parameter;
break;
}
*(p->password + p->idx++) = (char) b;
p->remaining--;
@ -77,9 +88,15 @@ enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b) {
break;
case param_new_ulen:
p->remaining = b;
if (p->remaining == 0)
p->state = cmd_error_invalid_parameter;
p->param_state = param_new_uname;
break;
case param_new_uname:
if (!is_valid(b)) {
p->state = cmd_error_invalid_parameter;
break;
}
*(p->new_username + p->idx++) = (char) b;
p->remaining--;
@ -101,10 +118,11 @@ enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b) {
case cmd_done:
case cmd_error_unsupported_version:
case cmd_error_unsupported_command:
case cmd_error_invalid_parameter:
case cmd_error_invalid_token:
break;
default:
fprintf(stderr, "unknown state %d\n", p->state);
fprintf(stderr, "Unknown state %d\n", p->state);
abort();
}
return p->state;
@ -114,7 +132,10 @@ extern bool cmd_is_done(const enum cmd_state state, bool * errored) {
bool ret = true;
switch (state) {
case cmd_error_unsupported_command:
case cmd_error_invalid_token:
case cmd_error_unsupported_version:
case cmd_error_invalid_parameter:
if (0 != errored) {
*errored = true;
}
@ -129,20 +150,23 @@ extern bool cmd_is_done(const enum cmd_state state, bool * errored) {
return ret;
}
extern const char * cmd_error(const struct cmd_parser * p) {
char * ret;
extern uint8_t cmd_error(const struct cmd_parser * p) {
uint8_t ret;
switch (p->state) {
case cmd_error_unsupported_version:
ret = "Unsupported version";
ret = CONFIG_VERSION_NOT_SUPPORTED;
break;
case cmd_error_unsupported_command:
ret = "Unsupported command";
ret = CMD_NOT_SUPPORTED_CMD;
break;
case cmd_error_invalid_token:
ret = "Invalid token";
ret = CONFIG_INVALID_TOKEN;
break;
case cmd_error_invalid_parameter:
ret = CONFIG_INVALID_PARAMETER;
break;
default:
ret = "";
ret = CONFIG_OK;
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 enum cmd_state cmd_consume(buffer * b, struct cmd_parser * p, bool * errored) {
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;
}
//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 TOKEN 0x0FF1CEDEADB00B1E
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;
if (!*p->verified)
if (!*p->verified) {
p->state = cmd_error_invalid_token;
}
}
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:
*selected = CMD_GET_METRICS;
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:
*selected = CMD_GET_USER_PAGES;
break;
case CMD_LIST_USERS:
*selected = CMD_LIST_USERS;
p->state = cmd_parameters;
p->param_state = param_byte;
p->remaining = 1;
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;
p->param_state = param_value;
p->remaining = 2;
break;
case 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->remaining = 1;
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:
*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)
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);
}
ssize_t cmd_process(struct selector_key *key, buffer * b) {
struct cmd_st *d = &ATTACHMENT(key)->client.cmd;
@ -165,23 +115,20 @@ ssize_t cmd_process(struct selector_key *key, buffer * b) {
return 0;
}
uint8_t status;
ssize_t i = 0;
buff[i++] = 0x01;
if (!d->verified) {
buff[i++] = 0xB0;
buffer_write_adv(b, i);
return i;
}
if (d->status == 0xFF || d->status == 0xD0 || d->status == 0xC0) {
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++] = d->status;
buffer_write_adv(b, i);
return i;
}
int ret;
uint64_t bytes;
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;
switch (d->cmd) {
@ -210,31 +157,56 @@ ssize_t cmd_process(struct selector_key *key, buffer * b) {
buff[i++] = (uint8_t) bytes;
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:
pages = get_user_pages();
buff[i++] = (uint8_t) (pages >> 8);
buff[i++] = (uint8_t) pages;
break;
case CMD_LIST_USERS:
break;
case CMD_GET_USER_LAST_CONNECTION:
if (!get_users((char *) buffer, d->value - 1)) {
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;
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;
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;
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;
case CMD_DELETE_USER:
status = delete_user(d->username);
if (!delete_user(d->username)) {
buff[status] = CONFIG_USER_NOT_FOUND;
break;
}
break;
case CMD_GET_PASSWORD_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:
set_auth_status(d->byte);
break;
case CMD_GET_PROXY_SERVER_STATUS:
break;
case CMD_CHANGE_PROXY_SERVER_STATUS:
break;
case CMD_RESTART_PROXY_SERVER:
break;
default:
fprintf(stderr, "Unknown command\n");
buff[i++] = 0xFE;
buff[status] = CONFIG_UNKNOWN_COMMAND;
break;
}
@ -264,7 +229,6 @@ ssize_t cmd_process(struct selector_key *key, buffer * b) {
return i;
}
// TODO: manejo de errores
void config_read(struct selector_key *key) {
struct cmd_st *d = &ATTACHMENT(key)->client.cmd;
bool error = false;
@ -281,7 +245,9 @@ void config_read(struct selector_key *key) {
buffer_write_adv(d->rb, n);
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 (cmd_process(key, d->wb) == 0)
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:
break;
default:
fprintf(stderr, "unknown state %d\n", p->state);
fprintf(stderr, "Unknown state %d\n", p->state);
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 size_t n = p->def->states_n[p->state];
bool matched = false;
bool matched;
for (unsigned i = 0; i < n ; i++) {
const int when = state[i].when;
if (state[i].when <= 0xFF) {
matched = (c == when);
} else if (state[i].when == ANY) {
} else if (state[i].when == (int) ANY) {
matched = true;
} else if (state[i].when > 0xFF) {
matched = (type & when);
} else {
matched = false;
matched = (type & when);
}
if (matched) {

View File

@ -55,17 +55,10 @@ struct parser_definition * parser_utils_strcmpi(const char *s) {
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;
}
// estados fijos
// Estados fijos
const size_t st_eq = n;
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_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;
}

View File

@ -212,46 +212,6 @@ extern int request_marshall(buffer * b, const enum socks_response_status status)
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 ret = status_general_SOCKS_server_failure;
switch (e) {

View File

@ -20,6 +20,7 @@
#include "socks5nio.h"
#include "confignio.h"
#include "buffer.h"
#include "server.h"
#define N(x) (sizeof(x)/sizeof((x)[0]))
@ -31,17 +32,42 @@ static void sigterm_handler(const int signal) {
}
static struct socks5args * args;
uint64_t config_token;
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));
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);
const char *err_msg = NULL;
selector_status ss = SELECTOR_SUCCESS;
fd_selector selector = NULL;
struct config * config_ret = NULL;
struct config * config_ret_ipv6 = NULL;
// ------
// TCP
@ -78,7 +104,10 @@ int main(int argc, char **argv) {
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));
@ -114,7 +143,10 @@ int main(int argc, char **argv) {
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_IPV6, IPV6_V6ONLY, &(int) { 1 }, sizeof(int));
@ -134,41 +166,112 @@ int main(int argc, char **argv) {
// 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;
memset(&udp_addr, 0, sizeof(udp_addr));
udp_addr.sin_family = AF_INET;
if (inet_pton(AF_INET, args->mng_addr, &udp_addr.sin_addr) <= 0) {
err_msg = "Incorrect network address";
goto finally;
}
// udp_addr.sin_addr.s_addr = htonl(INADDR_ANY);
udp_addr.sin_port = htons(args->mng_port);
int udp_server;
if (domain_udp == AF_INET || domain_udp == -1) {
memset(&udp_addr, 0, sizeof(udp_addr));
udp_addr.sin_family = AF_INET;
if (domain_udp == AF_INET) {
if (inet_pton(AF_INET, args->mng_addr, &udp_addr.sin_addr) <= 0) {
err_msg = "Incorrect network address";
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);
if (udp_server < 0) {
err_msg = "Unable to create UDP socket";
goto finally;
udp_server = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (udp_server < 0) {
err_msg = "Unable to create UDP socket";
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) {
err_msg = "Unable to bind UDP socket";
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 ::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(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 = {
.handle_read = config_read,
.handle_write = NULL,
.handle_close = NULL,
};
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_INET || domain_udp == -1) {
if (selector_fd_set_nio(udp_server) == -1) {
err_msg = "Getting config socket flags";
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;) {
@ -249,15 +367,18 @@ int main(int argc, char **argv) {
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].pass);
}
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) {
fprintf(stderr, "%s: %s\n", (err_msg == NULL) ? "": err_msg, ss == SELECTOR_IO ? strerror(errno) : selector_error(ss));
ret = 2;
@ -275,11 +396,20 @@ finally:
if (server >= 0) {
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;
}
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))
return i;
}
@ -290,36 +420,53 @@ int check_password(int idx, char * password) {
return !strcmp(args->users[idx].pass, password);
}
bool add_user(char * username, char * password) {
if (args->nusers < MAX_USERS) {
user_t * user = malloc(sizeof(user_t));
user->name = malloc(strlen(username) + 1);
strcpy(user->name, username);
user->pass = malloc(strlen(password) + 1);
strcpy(user->pass, password);
args->users[args->nusers] = *user;
args->nusers++;
return true;
int add_user(char * username, char * password) {
if (findUser(username) == -1) {
if (args->nusers < MAX_USERS) {
int len = strlen(username) + 1;
args->users[args->nusers].name = malloc(len);
if (args->users[args->nusers].name == NULL) {
return -1;
}
strcpy(args->users[args->nusers].name, username);
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);
if (idx == -1)
return false;
args->users[idx].name = realloc(args->users[idx].name, strlen(new_uname) + 1);
return 0;
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);
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);
if (idx == -1)
return false;
args->users[idx].pass = realloc(args->users[idx].pass, strlen(new_pwd) + 1);
return 0;
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);
return true;
return 1;
}
bool delete_user(char * uname) {
@ -328,8 +475,38 @@ bool delete_user(char * uname) {
return false;
free(args->users[idx].name);
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->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;
}
uint8_t verify_token(uint64_t token) {
return token == config_token;
}

View File

@ -24,10 +24,10 @@
#include "parser_utils.h"
#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 USER_MAX_SIZE 249
// TODO: hacer que cambie con nuestro proto
bool auth_active = true;
bool pwd_dissector_active = false;
@ -56,6 +56,7 @@ enum socks_v5state {
DONE,
HELLO_ERROR,
AUTH_ERROR,
REQUEST_ERROR,
ERROR,
};
@ -108,6 +109,7 @@ struct auth_st {
/** buffer utilizado para I/O */
buffer *rb, *wb;
struct auth_parser parser;
char * username;
uint8_t verified;
};
@ -193,6 +195,7 @@ struct socks5 {
unsigned references;
bool parser;
char * username;
struct socks5 * next;
};
@ -236,6 +239,7 @@ static struct socks5 * socks5_new(int client_fd) {
stm_init(&ret->stm);
ret->parser = false;
ret->username = NULL;
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);
@ -266,10 +270,13 @@ void parsers_destroy(struct socks5 * s) {
/** realmente destruye */
static void
socks5_destroy_(struct socks5 * s) {
if(s->origin_resolution != NULL) {
if (s->origin_resolution != NULL) {
freeaddrinfo(s->origin_resolution);
s->origin_resolution = 0;
}
if (s->username != NULL) {
free(s->username);
}
free(s);
}
@ -282,6 +289,13 @@ socks5_destroy(struct socks5 * s) {
if (s != NULL) {
if (s->references == 1) {
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--;
if(pool_size < max_pool) {
s->next = pool;
@ -339,7 +353,7 @@ void socksv5_passive_accept(struct selector_key *key) {
goto fail;
}
state = socks5_new(client);
if(state == NULL) {
if (state == NULL) {
// sin un estado, nos es imposible manejaro.
// tal vez deberiamos apagar accept() hasta que detectemos
// 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);
}
// return error ? ERROR : 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' */
static void on_auth_password(struct auth_parser * p, char * password) {
uint8_t * verified = p->verified;
if (check_password(p->user_pos, password))
* verified = 1;
if (p->user_pos >= 0) {
if (check_password(p->user_pos, password))
*verified = 1;
}
}
/** 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.on_username = on_auth_username;
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.idx = 0;
auth_parser_init(&d->parser);
@ -552,7 +569,12 @@ static unsigned auth_read(struct selector_key * key) {
ret = ERROR;
}
return error ? ERROR : ret;
if (error) {
ret = AUTH_ERROR;
selector_set_interest_key(key, OP_WRITE);
}
return ret;
}
/** 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) {
ret = ERROR;
}
if (!v) {
ret = AUTH_ERROR;
}
return ret;
}
@ -599,6 +624,10 @@ static unsigned auth_write(struct selector_key * key) {
return ret;
}
static unsigned auth_write_error(struct selector_key * key) {
auth_write(key);
return ERROR;
}
////////////////////////////////////////////////////////////////////////////////
// REQUEST
@ -651,7 +680,6 @@ static unsigned request_read(struct selector_key * key) {
selector_set_interest_key(key, OP_WRITE);
}
// return error ? ERROR : 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;
d->request.dest_addr.ipv4.sin_port = d->request.dest_port;
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));
ret = request_connect(key, d);
break;
@ -677,20 +704,19 @@ static unsigned request_process(struct selector_key * key, struct request_st * d
ATTACHMENT(key)->origin_domain = AF_INET6;
d->request.dest_addr.ipv6.sin6_port = d->request.dest_port;
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));
ret = request_connect(key, d);
break;
} case socks_req_addr_domain: {
struct selector_key * k = malloc(sizeof(*key));
if (k == NULL) {
ret = REQUEST_WRITE;
ret = REQUEST_ERROR;
d->status = status_general_SOCKS_server_failure;
selector_set_interest_key(key, OP_WRITE);
} else {
memcpy(k, key, sizeof(*k));
if (-1 == pthread_create(&tid, 0, request_resolv_blocking, k)) {
ret = REQUEST_WRITE;
ret = REQUEST_ERROR;
d->status = status_general_SOCKS_server_failure;
selector_set_interest_key(key, OP_WRITE);
} else {
@ -740,13 +766,17 @@ static void * request_resolv_blocking(void * data) {
char buff[7];
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);
if (ret != 0) {
switch (ret) {
case EAI_FAMILY:
s->client.request.status = status_address_type_not_supported;
break;
case EAI_FAIL:
s->client.request.status = status_host_unreachable;
break;
default:
s->client.request.status = status_network_unreachable;
break;
}
}
@ -761,32 +791,16 @@ static unsigned request_resolv_done(struct selector_key * key) {
struct socks5 * s = ATTACHMENT(key);
unsigned int st = REQUEST_CONNECTING;
if (d->status == status_address_type_not_supported && d->status == status_host_unreachable)
return st;
if (d->status == status_address_type_not_supported || d->status == status_host_unreachable || d->status == status_network_unreachable) {
return request_connect(key, d);
}
if (s->origin_resolution == 0) {
d->status = status_general_SOCKS_server_failure;
}
else {
struct addrinfo * addr = s->origin_resolution;
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;
}
s->origin_resolution_current = s->origin_resolution;
st = request_connect(key, d);
return st;
}
@ -794,6 +808,13 @@ static unsigned request_connect(struct selector_key * key, struct request_st * d
bool error = false;
enum socks_response_status status = d->status;
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);
if (*fd == -1) {
@ -819,9 +840,11 @@ static unsigned request_connect(struct selector_key * key, struct request_st * d
}
ATTACHMENT(key)->references += 1;
} else {
status = errno_to_socks(errno);
error = true;
goto finally;
if (s->origin_resolution_current == NULL || s->origin_resolution_current->ai_next == NULL) {
status = errno_to_socks(errno);
error = true;
goto finally;
}
}
} else {
abort();
@ -833,6 +856,10 @@ finally:
close(*fd);
*fd = -1;
}
request_marshall(d->wb, d->status);
selector_set_interest_key(key, OP_WRITE);
return REQUEST_ERROR;
}
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) {
int error;
int error = 0;
socklen_t len = sizeof(error);
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) {
*d->status = status_general_SOCKS_server_failure;
} else {
if (error == 0) {
*d->status = status_succeeded;
*d->origin_fd = key->fd;
} else {
*d->status = errno_to_socks(error);
if (getsockopt(key->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error) {
if (sx->origin_resolution_current != NULL && sx->origin_resolution_current->ai_next != NULL) {
sx->origin_resolution_current = sx->origin_resolution_current->ai_next;
return request_connect(key, req);
}
*d->status = errno_to_socks(error);
} else {
*d->status = status_succeeded;
*d->origin_fd = key->fd;
}
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;
}
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};
unsigned n = N(cbuff);
time_t now = 0;
time(&now);
strftime(cbuff, n, "%FT%TZ\t", gmtime(&now));
strftime(cbuff, n, "%FT%TZ ", gmtime(&now));
size_t len = strlen(cbuff);
sockaddr_to_human(cbuff + len, N(cbuff) - len, client_addr);
strncat(cbuff, "\t", n - 1);
strncat(cbuff, " ", n - 1);
cbuff[n - 1] = 0;
len = strlen(cbuff);
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");
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);
}
@ -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;
}
@ -948,20 +1031,19 @@ static void copy_init(const unsigned state, struct selector_key * key) {
d->duplex = OP_READ | OP_WRITE;
d->other = &ATTACHMENT(key)->orig.copy;
// struct parser_definition * user = parser_utils_strcmpi("user");
// d->parser_user = parser_init(parser_no_classes(), user);
// struct parser_definition * pass = parser_utils_strcmpi("pass");
// d->parser_pass = parser_init(parser_no_classes(), pass);
// d->user = malloc(249);
// d->pass = malloc(249);
d->user_done = false;
d->pass_done = false;
d->parser_user = parser_init(parser_no_classes(), user);
d->parser_pass = parser_init(parser_no_classes(), pass);
d->user = malloc(249);
d->pass = malloc(249);
ATTACHMENT(key)->parser = true;
if (pwd_dissector_active) {
d->user_done = false;
d->pass_done = false;
d->parser_user = parser_init(parser_no_classes(), user);
d->parser_pass = parser_init(parser_no_classes(), pass);
d->user = malloc(USER_MAX_SIZE);
d->pass = malloc(USER_MAX_SIZE);
ATTACHMENT(key)->parser = true;
}
else {
d->parser_user = NULL;
d->parser_pass = NULL;
}
d = &ATTACHMENT(key)->orig.copy;
d->fd = &ATTACHMENT(key)->origin_fd;
@ -1046,12 +1128,7 @@ static unsigned copy_r(struct selector_key * key) {
if (*(ptr + i) == '\n') {
d->pass_done = true;
d->pass[k - 1] = 0;
char buff[SOCKADDR_TO_HUMAN_MIN + 2] = {0};
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);
log_request_password((const struct sockaddr *) &ATTACHMENT(key)->origin_addr, ATTACHMENT(key)->username, d->user, d->pass);
d->user_done = false;
d->pass_done = false;
parser_reset(d->parser_user);
@ -1147,6 +1224,9 @@ static const struct state_definition client_statbl[] = {
}, {
.state = HELLO_ERROR,
.on_write_ready = hello_write_error,
}, {
.state = AUTH_ERROR,
.on_write_ready = auth_write_error,
}, {
.state = REQUEST_ERROR,
.on_write_ready = request_write_error,