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:
parent
23ee49e49f
commit
f8aa3e12e3
3
Makefile
3
Makefile
|
@ -1,8 +1,7 @@
|
||||||
CCFLAGS = -std=c11 -Wall -Wextra -Wno-unused-parameter -Wno-implicit-fallthrough -pedantic -pedantic-errors -fsanitize=address -fno-omit-frame-pointer -g -D_POSIX_C_SOURCE=200809L
|
CCFLAGS = -std=c11 -Wall -Wextra -Wno-unused-parameter -Wno-implicit-fallthrough -pedantic -pedantic-errors -fsanitize=address -fno-omit-frame-pointer -g -D_POSIX_C_SOURCE=200809L
|
||||||
LDFLAGS = -lpthread -lm
|
LDFLAGS = -lpthread -lm
|
||||||
|
|
||||||
# SERVER_SOURCES=src/args.c src/selector.c src/socks5nio.c src/confignio.c src/stm.c src/hello.c src/request.c src/buffer.c src/server.c
|
SERVER_SOURCES=src/args.c src/selector.c src/socks5nio.c src/confignio.c src/stm.c src/hello.c src/request.c src/netutils.c src/buffer.c src/server.c src/auth.c src/cmd.c src/parser.c src/parser_utils.c
|
||||||
SERVER_SOURCES=src/args.c src/selector.c src/socks5nio.c src/confignio.c src/stm.c src/hello.c src/request.c src/buffer.c src/server.c src/auth.c src/cmd.c
|
|
||||||
CLIENT_SOURCES=src/client.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
|
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_LIBS=
|
||||||
|
|
|
@ -53,14 +53,14 @@ Tabla de Contenidos
|
||||||
[] 5. reportar los fallos a los clientes usando toda la potencia del
|
[] 5. reportar los fallos a los clientes usando toda la potencia del
|
||||||
protocolo.
|
protocolo.
|
||||||
|
|
||||||
[] 6. implementar mecanismos que permitan recolectar métricas que
|
[X] 6. implementar mecanismos que permitan recolectar métricas que
|
||||||
ayuden a monitorear la operación del sistema.
|
ayuden a monitorear la operación del sistema.
|
||||||
|
|
||||||
A. cantidad de conexiones históricas
|
[]A. cantidad de conexiones históricas
|
||||||
|
|
||||||
B. cantidad de conexiones concurrentes
|
[]B. cantidad de conexiones concurrentes
|
||||||
|
|
||||||
C. cantidad de bytes transferidos
|
[X]C. cantidad de bytes transferidos
|
||||||
|
|
||||||
D. cualquier otra métrica que considere oportuno para el
|
D. cualquier otra métrica que considere oportuno para el
|
||||||
entendimiento del funcionamiento dinámico del sistema
|
entendimiento del funcionamiento dinámico del sistema
|
||||||
|
@ -68,14 +68,14 @@ Tabla de Contenidos
|
||||||
Las métricas PUEDEN ser volátiles (si se reinicia el servidor las
|
Las métricas PUEDEN ser volátiles (si se reinicia el servidor las
|
||||||
estadísticas pueden perderse).
|
estadísticas pueden perderse).
|
||||||
|
|
||||||
[] 7. implementar mecanismos que permitan manejar usuarios cambiar la
|
[X] 7. implementar mecanismos que permitan manejar usuarios cambiar la
|
||||||
configuración del servidor en tiempo de ejecución sin reiniciar
|
configuración del servidor en tiempo de ejecución sin reiniciar
|
||||||
el servidor. Las diferentes implementaciones PUEDEN decidir
|
el servidor. Las diferentes implementaciones PUEDEN decidir
|
||||||
disponibilizar otros cambios de ejecución en tiempo de ejecución
|
disponibilizar otros cambios de ejecución en tiempo de ejecución
|
||||||
de otras configuraciones (memoria utilizada en I/O, timeouts,
|
de otras configuraciones (memoria utilizada en I/O, timeouts,
|
||||||
etc).
|
etc).
|
||||||
|
|
||||||
[] 8. implementar un registro de acceso que permitan a un administrador
|
[X] 8. implementar un registro de acceso que permitan a un administrador
|
||||||
entender los accesos de cada uno de los usuarios. Pensar en el
|
entender los accesos de cada uno de los usuarios. Pensar en el
|
||||||
caso de que llega una queja externa y el administrador debe saber
|
caso de que llega una queja externa y el administrador debe saber
|
||||||
quien fue el que se conectó a cierto sitio web y cuando.
|
quien fue el que se conectó a cierto sitio web y cuando.
|
||||||
|
|
370
docs/rfc.txt
370
docs/rfc.txt
|
@ -7,7 +7,7 @@ Bottler Protocol version 1
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
|
|
||||||
Unless otherwise noted, the decimal numbers appearing in packet-
|
Unless otherwise noted, the decimal numbers appearing in packet -
|
||||||
format diagrams represent the length of the corresponding field, in
|
format diagrams represent the length of the corresponding field, in
|
||||||
octets. Where a given octet must take on a specific value, the
|
octets. Where a given octet must take on a specific value, the
|
||||||
syntax X'hh' is used to denote the value of the single octet in that
|
syntax X'hh' is used to denote the value of the single octet in that
|
||||||
|
@ -15,15 +15,11 @@ Note:
|
||||||
corresponding field has a variable length defined either by an
|
corresponding field has a variable length defined either by an
|
||||||
associated (one or two octet) length field, or by a data type field.
|
associated (one or two octet) length field, or by a data type field.
|
||||||
|
|
||||||
2. Procedure
|
NETWORK ORDER.
|
||||||
|
|
||||||
A client MUST send its datagrams to the UDP relay server at
|
2. Requests
|
||||||
the UDP port indicated by BND.PORT in the reply to the UDP ASSOCIATE
|
|
||||||
request. If the selected authentication method provides
|
The requested is formed as follows:
|
||||||
encapsulation for the purposes of authenticity, integrity, and/or
|
|
||||||
confidentiality, the datagram MUST be encapsulated using the
|
|
||||||
appropriate encapsulation. Each UDP datagram carries a UDP request
|
|
||||||
header with it:
|
|
||||||
|
|
||||||
+-----+-------+-------+--------------+
|
+-----+-------+-------+--------------+
|
||||||
| VER | TOKEN | CMD | PARAMETERS |
|
| VER | TOKEN | CMD | PARAMETERS |
|
||||||
|
@ -59,99 +55,220 @@ Note:
|
||||||
o X'11' START/STOP PROXY SERVER
|
o X'11' START/STOP PROXY SERVER
|
||||||
o X'12' RESET PROXY SERVER
|
o X'12' RESET PROXY SERVER
|
||||||
|
|
||||||
|
TODO: metodo para saber cuanto tiene una página? o lo hardcodeamos en el proto?
|
||||||
|
|
||||||
When a UDP relay server decides to relay a UDP datagram, it does so
|
// habría que explicar cada uno, no?
|
||||||
silently, without any notification to the requesting client.
|
|
||||||
Similarly, it will drop datagrams it cannot or will not relay. When
|
|
||||||
a UDP relay server receives a reply datagram from a remote host, it
|
|
||||||
MUST encapsulate that datagram using the above UDP request header,
|
|
||||||
and any authentication-method-dependent encapsulation.
|
|
||||||
|
|
||||||
The FRAG field indicates whether this datagram is one of a
|
2. Commands
|
||||||
number of fragments or not. If implemented, the high-order bit indicates
|
|
||||||
end-of-fragment sequence, while a value of X'00' indicates that this
|
|
||||||
datagram is standalone. Values between 1 and 127 indicate the
|
|
||||||
fragment position within a fragment sequence. Each receiver will
|
|
||||||
have a REASSEMBLY QUEUE and a REASSEMBLY TIMER associated with these
|
|
||||||
fragments. The reassembly queue must be reinitialized and the
|
|
||||||
associated fragments abandoned whenever the REASSEMBLY TIMER expires,
|
|
||||||
or a new datagram arrives carrying a FRAG field whose value is less
|
|
||||||
than the highest FRAG value processed for this fragment sequence.
|
|
||||||
The reassembly timer MUST be no less than 5 seconds. It is
|
|
||||||
recommended that fragmentation be avoided by applications wherever
|
|
||||||
possible.
|
|
||||||
|
|
||||||
Implementation of fragmentation is optional; an implementation that
|
CMD: X'00' - GET METRICS
|
||||||
does not support fragmentation MUST drop any datagram whose FRAG
|
|
||||||
field is other than X'00'.
|
|
||||||
|
|
||||||
3. Requests
|
Requests historical metrics values.
|
||||||
|
Response comes as n integers taking 4 bytes each. (representing)
|
||||||
|
|
||||||
Once the method-dependent subnegotiation has completed, the client
|
Request:
|
||||||
sends the request details. If the negotiated method includes
|
+-------+-------+---------+
|
||||||
encapsulation for purposes of integrity checking and/or
|
| VER | TOKEN | CMD |
|
||||||
confidentiality, these requests MUST be encapsulated in the method -
|
+-------+-------+---------+
|
||||||
dependent encapsulation.
|
| X'01' | 8 | X'00' |
|
||||||
|
+-------+-------+---------+
|
||||||
|
|
||||||
The SOCKS request is formed as follows:
|
Response:
|
||||||
|
+-------+--------+----------+
|
||||||
|
| VER | CODE | RESPONSE | TODO: aca hay que definir cuanto ocupa cada metrica
|
||||||
|
+-------+--------+----------+ TODO: unknown command 0xFE
|
||||||
|
| X'01' | 1 | | TODO: get users de ettercap
|
||||||
|
+-------+--------+----------+
|
||||||
|
|
||||||
+----+-----+-------+------+----------+----------+
|
The possible values for CODE are:
|
||||||
|VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
|
|
||||||
+----+-----+-------+------+----------+----------+
|
|
||||||
| 1 | 1 | X'00' | 1 | Variable | 2 |
|
|
||||||
+----+-----+-------+------+----------+----------+
|
|
||||||
|
|
||||||
Where:
|
o X'00' OK
|
||||||
|
o X'B0' INVALID TOKEN
|
||||||
|
o X'D0' VERSION NOT SUPPORTED
|
||||||
|
o X'FF' METHOD NOT SUPPORTED
|
||||||
|
|
||||||
o VER protocol version: X'05'
|
CMD: X'01' - GET BUFFER SIZE
|
||||||
o CMD
|
|
||||||
o CONNECT X'01'
|
|
||||||
o BIND X'02'
|
|
||||||
o UDP ASSOCIATE X'03'
|
|
||||||
o RSV RESERVED
|
|
||||||
o ATYP address type of following address
|
|
||||||
o IP V4 address: X'01'
|
|
||||||
o DOMAINNAME: X'03'
|
|
||||||
o IP V6 address: X'04'
|
|
||||||
o DST.ADDR desired destination address
|
|
||||||
o DST.PORT desired destination port in network octet
|
|
||||||
order
|
|
||||||
|
|
||||||
The SOCKS server will typically evaluate the request based on source
|
Requests buffer size used for the proxy SOCKS server.
|
||||||
and destination addresses, and return one or more reply messages, as
|
Response comes with a response code and one integer
|
||||||
appropriate for the request type.
|
representing the buffer size taking 2 bytes.
|
||||||
|
|
||||||
5. Addressing
|
Request:
|
||||||
|
+-------+-------+---------+
|
||||||
|
| VER | TOKEN | CMD |
|
||||||
|
+-------+-------+---------+
|
||||||
|
| X'01' | 8 | X'01' |
|
||||||
|
+-------+-------+---------+
|
||||||
|
|
||||||
In an address field (DST.ADDR, BND.ADDR), the ATYP field specifies
|
Response:
|
||||||
the type of address contained within the field:
|
+-------+--------+-----------+
|
||||||
|
| VER | CODE | BUFF SIZE |
|
||||||
|
+-------+--------+-----------+
|
||||||
|
| X'01' | 1 | 2 |
|
||||||
|
+-------+--------+-----------+
|
||||||
|
|
||||||
o X'01'
|
The possible values for CODE are:
|
||||||
|
|
||||||
the address is a version-4 IP address, with a length of 4 octets
|
o X'00' OK
|
||||||
|
o X'B0' INVALID TOKEN
|
||||||
|
o X'D0' VERSION NOT SUPPORTED
|
||||||
|
o X'FF' METHOD NOT SUPPORTED
|
||||||
|
|
||||||
o X'03'
|
CMD: X'02' - SET BUFFER SIZE
|
||||||
|
|
||||||
the address field contains a fully-qualified domain name. The first
|
TODO: decidir bien los tamaños
|
||||||
octet of the address field contains the number of octets of name that
|
|
||||||
follow, there is no terminating NUL octet.
|
|
||||||
|
|
||||||
o X'04'
|
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
|
||||||
|
|
||||||
the address is a version-6 IP address, with a length of 16 octets.
|
Request:
|
||||||
|
+-------+-------+---------+-----------+
|
||||||
|
| VER | TOKEN | CMD | BUFF SIZE |
|
||||||
|
+-------+-------+---------+-----------+
|
||||||
|
| X'01' | 8 | X'02' | 2 |
|
||||||
|
+-------+-------+---------+-----------+
|
||||||
|
|
||||||
6. Replies
|
Response:
|
||||||
|
+-------+--------+
|
||||||
|
| VER | CODE |
|
||||||
|
+-------+--------+
|
||||||
|
| X'01' | 1 |
|
||||||
|
+-------+--------+
|
||||||
|
|
||||||
|
The possible values for CODE are:
|
||||||
|
|
||||||
|
o X'00' OK
|
||||||
|
o X'B0' INVALID TOKEN
|
||||||
|
o X'C0' INVALID PARAMETER VALUE
|
||||||
|
o X'D0' VERSION NOT SUPPORTED
|
||||||
|
o X'FF' METHOD NOT SUPPORTED
|
||||||
|
|
||||||
|
CMD: X'03' - GET TIMEOUT VALUE
|
||||||
|
|
||||||
|
Requests the timeout value used in the proxy SOCKS server.
|
||||||
|
Response comes with a response code and one integer
|
||||||
|
representing the timeout value taking 2 bytes.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
+-------+-------+---------+
|
||||||
|
| VER | TOKEN | CMD |
|
||||||
|
+-------+-------+---------+
|
||||||
|
| X'01' | 8 | X'03' |
|
||||||
|
+-------+-------+---------+
|
||||||
|
|
||||||
|
Response:
|
||||||
|
+-------+--------+---------+
|
||||||
|
| VER | CODE | TIMEOUT |
|
||||||
|
+-------+--------+---------+
|
||||||
|
| X'01' | 1 | 2 |
|
||||||
|
+-------+--------+---------+
|
||||||
|
|
||||||
|
The possible values for CODE are:
|
||||||
|
|
||||||
|
o X'00' OK
|
||||||
|
o X'B0' INVALID TOKEN
|
||||||
|
o X'D0' VERSION NOT SUPPORTED
|
||||||
|
o X'FF' METHOD NOT SUPPORTED
|
||||||
|
|
||||||
|
CMD: X'04' - SET TIMEOUT VALUE
|
||||||
|
|
||||||
|
TODO: decidir bien los valores
|
||||||
|
|
||||||
|
Requests the modification of the timeout value used in the
|
||||||
|
proxy SOCKS server. Value must be between 128 and 2048
|
||||||
|
Response comes with a response code indicating the output of the action required
|
||||||
|
|
||||||
|
Request:
|
||||||
|
+-------+-------+---------+---------+
|
||||||
|
| VER | TOKEN | CMD | TIMEOUT |
|
||||||
|
+-------+-------+---------+---------+
|
||||||
|
| X'01' | 8 | X'04' | 2 |
|
||||||
|
+-------+-------+---------+---------+
|
||||||
|
|
||||||
|
Response:
|
||||||
|
+-------+--------+
|
||||||
|
| VER | CODE |
|
||||||
|
+-------+--------+
|
||||||
|
| X'01' | 1 |
|
||||||
|
+-------+--------+
|
||||||
|
|
||||||
|
The possible values for CODE are:
|
||||||
|
|
||||||
|
o X'00' OK
|
||||||
|
o X'B0' INVALID TOKEN
|
||||||
|
o X'C0' INVALID PARAMETER VALUE
|
||||||
|
o X'D0' VERSION NOT SUPPORTED
|
||||||
|
o X'FF' METHOD NOT SUPPORTED
|
||||||
|
|
||||||
|
CMD: X'05' - GET USER PAGES
|
||||||
|
|
||||||
|
Requests amount of pages of valid users for the proxy SOCKS server.
|
||||||
|
Response comes as an integers taking 2 bytes. (representing)
|
||||||
|
|
||||||
|
Request:
|
||||||
|
+-------+-------+---------+
|
||||||
|
| VER | TOKEN | CMD |
|
||||||
|
+-------+-------+---------+
|
||||||
|
| X'01' | 8 | X'05' |
|
||||||
|
+-------+-------+---------+
|
||||||
|
|
||||||
|
Response:
|
||||||
|
+-------+--------+-------+
|
||||||
|
| VER | CODE | PAGES |
|
||||||
|
+-------+--------+-------+
|
||||||
|
| 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'06' - LIST USERS
|
||||||
|
|
||||||
|
Requests amount of pages of valid users for the proxy SOCKS server.
|
||||||
|
Response comes as an integers taking 2 bytes. (representing)
|
||||||
|
|
||||||
|
Request:
|
||||||
|
+-------+-------+---------+--------+
|
||||||
|
| VER | TOKEN | CMD | PAGE |
|
||||||
|
+-------+-------+---------+--------+
|
||||||
|
| X'01' | 8 | X'06' | 2 |
|
||||||
|
+-------+-------+---------+--------+
|
||||||
|
|
||||||
|
Response:
|
||||||
|
+-------+--------+---------------+
|
||||||
|
| VER | CODE | PAGE |
|
||||||
|
+-------+--------+---------------+
|
||||||
|
| X'01' | 1 | Page size |
|
||||||
|
+-------+--------+---------------+
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
3. Replies
|
||||||
|
|
||||||
The SOCKS request information is sent by the client as soon as it has
|
The SOCKS request information is sent by the client as soon as it has
|
||||||
established a connection to the SOCKS server, and completed the
|
established a connection to the SOCKS server, and completed the
|
||||||
authentication negotiations. The server evaluates the request, and
|
authentication negotiations. The server evaluates the request, and
|
||||||
returns a reply formed as follows:
|
returns a reply formed as follows:
|
||||||
|
|
||||||
+----+-----+-------+------+----------+----------+
|
+----+-----+
|
||||||
|VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
|
|VER | REP |
|
||||||
+----+-----+-------+------+----------+----------+
|
+----+-----+
|
||||||
| 1 | 1 | X'00' | 1 | Variable | 2 |
|
| 1 | 1 |
|
||||||
+----+-----+-------+------+----------+----------+
|
+----+-----+
|
||||||
|
|
||||||
Where:
|
Where:
|
||||||
|
|
||||||
|
@ -167,104 +284,5 @@ Note:
|
||||||
o X'07' Command not supported
|
o X'07' Command not supported
|
||||||
o X'08' Address type not supported
|
o X'08' Address type not supported
|
||||||
o X'09' to X'FF' unassigned
|
o X'09' to X'FF' unassigned
|
||||||
o RSV RESERVED
|
|
||||||
o ATYP address type of following address
|
|
||||||
o IP V4 address: X'01'
|
|
||||||
o DOMAINNAME: X'03'
|
|
||||||
o IP V6 address: X'04'
|
|
||||||
o BND.ADDR server bound address
|
|
||||||
o BND.PORT server bound port in network octet order
|
|
||||||
|
|
||||||
Fields marked RESERVED (RSV) must be set to X'00'.
|
|
||||||
|
|
||||||
If the chosen method includes encapsulation for purposes of
|
|
||||||
authentication, integrity and/or confidentiality, the replies are
|
|
||||||
encapsulated in the method-dependent encapsulation.
|
|
||||||
|
|
||||||
CONNECT
|
|
||||||
|
|
||||||
In the reply to a CONNECT, BND.PORT contains the port number that the
|
|
||||||
server assigned to connect to the target host, while BND.ADDR
|
|
||||||
contains the associated IP address. The supplied BND.ADDR is often
|
|
||||||
different from the IP address that the client uses to reach the SOCKS
|
|
||||||
server, since such servers are often multi-homed. It is expected
|
|
||||||
that the SOCKS server will use DST.ADDR and DST.PORT, and the
|
|
||||||
client-side source address and port in evaluating the CONNECT
|
|
||||||
request.
|
|
||||||
|
|
||||||
BIND
|
|
||||||
|
|
||||||
The BIND request is used in protocols which require the client to
|
|
||||||
accept connections from the server. FTP is a well-known example,
|
|
||||||
which uses the primary client-to-server connection for commands and
|
|
||||||
status reports, but may use a server-to-client connection for
|
|
||||||
transferring data on demand (e.g. LS, GET, PUT).
|
|
||||||
|
|
||||||
It is expected that the client side of an application protocol will
|
|
||||||
use the BIND request only to establish secondary connections after a
|
|
||||||
primary connection is established using CONNECT. In is expected that
|
|
||||||
a SOCKS server will use DST.ADDR and DST.PORT in evaluating the BIND
|
|
||||||
request.
|
|
||||||
|
|
||||||
Two replies are sent from the SOCKS server to the client during a
|
|
||||||
BIND operation. The first is sent after the server creates and binds
|
|
||||||
a new socket. The BND.PORT field contains the port number that the
|
|
||||||
SOCKS server assigned to listen for an incoming connection. The
|
|
||||||
BND.ADDR field contains the associated IP address. The client will
|
|
||||||
typically use these pieces of information to notify (via the primary
|
|
||||||
or control connection) the application server of the rendezvous
|
|
||||||
address. The second reply occurs only after the anticipated incoming
|
|
||||||
connection succeeds or fails.
|
|
||||||
|
|
||||||
In the second reply, the BND.PORT and BND.ADDR fields contain the
|
|
||||||
address and port number of the connecting host.
|
|
||||||
|
|
||||||
UDP ASSOCIATE
|
|
||||||
|
|
||||||
The UDP ASSOCIATE request is used to establish an association within
|
|
||||||
the UDP relay process to handle UDP datagrams. The DST.ADDR and
|
|
||||||
DST.PORT fields contain the address and port that the client expects
|
|
||||||
to use to send UDP datagrams on for the association. The server MAY
|
|
||||||
use this information to limit access to the association. If the
|
|
||||||
client is not in possesion of the information at the time of the UDP
|
|
||||||
ASSOCIATE, the client MUST use a port number and address of all
|
|
||||||
zeros.
|
|
||||||
|
|
||||||
A UDP association terminates when the TCP connection that the UDP
|
|
||||||
ASSOCIATE request arrived on terminates.
|
|
||||||
|
|
||||||
In the reply to a UDP ASSOCIATE request, the BND.PORT and BND.ADDR
|
|
||||||
fields indicate the port number/address where the client MUST send
|
|
||||||
UDP request messages to be relayed.
|
|
||||||
|
|
||||||
Reply Processing
|
|
||||||
|
|
||||||
When a reply (REP value other than X'00') indicates a failure, the
|
|
||||||
SOCKS server MUST terminate the TCP connection shortly after sending
|
|
||||||
the reply. This must be no more than 10 seconds after detecting the
|
|
||||||
condition that caused a failure.
|
|
||||||
|
|
||||||
If the reply code (REP value of X'00') indicates a success, and the
|
|
||||||
request was either a BIND or a CONNECT, the client may now start
|
|
||||||
passing data. If the selected authentication method supports
|
|
||||||
encapsulation for the purposes of integrity, authentication and/or
|
|
||||||
confidentiality, the data are encapsulated using the method-dependent
|
|
||||||
encapsulation. Similarly, when data arrives at the SOCKS server for
|
|
||||||
the client, the server MUST encapsulate the data as appropriate for
|
|
||||||
the authentication method in use.
|
|
||||||
|
|
||||||
|
|
||||||
8. Security Considerations
|
|
||||||
|
|
||||||
This document describes a protocol for the application-layer
|
|
||||||
traversal of IP network firewalls. The security of such traversal is
|
|
||||||
highly dependent on the particular authentication and encapsulation
|
|
||||||
methods provided in a particular implementation, and selected during
|
|
||||||
negotiation between SOCKS client and SOCKS server.
|
|
||||||
|
|
||||||
Careful consideration should be given by the administrator to the
|
|
||||||
selection of authentication methods.
|
|
||||||
|
|
||||||
9. References
|
9. References
|
||||||
|
|
||||||
[1] Koblas, D., "SOCKS", Proceedings: 1992 Usenix Security Symposium.
|
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
|
|
||||||
#define MAX_USERS 10
|
#define MAX_USERS 10
|
||||||
|
|
||||||
struct users {
|
typedef struct user_t {
|
||||||
char * name;
|
char * name;
|
||||||
char * pass;
|
char * pass;
|
||||||
};
|
} user_t;
|
||||||
|
|
||||||
struct socks5args {
|
struct socks5args {
|
||||||
char * socks_addr;
|
char * socks_addr;
|
||||||
|
@ -17,11 +17,11 @@ struct socks5args {
|
||||||
char * mng_addr;
|
char * mng_addr;
|
||||||
unsigned short mng_port;
|
unsigned short mng_port;
|
||||||
|
|
||||||
bool disectors_enabled;
|
bool dissector_enabled;
|
||||||
|
|
||||||
int nusers;
|
int nusers;
|
||||||
|
|
||||||
struct users users[MAX_USERS];
|
user_t users[MAX_USERS];
|
||||||
};
|
};
|
||||||
|
|
||||||
void parse_args(int argc, char ** argv, struct socks5args * args);
|
void parse_args(int argc, char ** argv, struct socks5args * args);
|
||||||
|
|
|
@ -1,4 +1,30 @@
|
||||||
#ifndef CLIENT_H
|
#ifndef CLIENT_H
|
||||||
#define CLIENT_H
|
#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 RESPONSE_OK 0x00
|
||||||
|
#define RESPONSE_INVALID_TOKEN 0xB0
|
||||||
|
#define RESPONSE_VERSION_NOT_SUPPORTED 0xD0
|
||||||
|
#define RESPONSE_CMD_NOT_SUPPORTED 0xFF
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
|
#define STR_SIZE 255
|
||||||
|
|
||||||
#define CMD_GET_METRICS 0x00
|
#define CMD_GET_METRICS 0x00
|
||||||
#define CMD_GET_BUFFER_SIZE 0x01
|
#define CMD_GET_BUFFER_SIZE 0x01
|
||||||
#define CMD_SET_BUFFER_SIZE 0x02
|
#define CMD_SET_BUFFER_SIZE 0x02
|
||||||
|
@ -67,11 +69,11 @@ struct cmd_parser {
|
||||||
|
|
||||||
uint8_t idx;
|
uint8_t idx;
|
||||||
|
|
||||||
char username[255];
|
char * username;
|
||||||
char new_username[255];
|
char * new_username;
|
||||||
char password[255];
|
char * password;
|
||||||
uint8_t byte;
|
uint8_t * byte;
|
||||||
uint16_t value;
|
uint16_t * value;
|
||||||
|
|
||||||
void * parameters;
|
void * parameters;
|
||||||
};
|
};
|
||||||
|
@ -88,6 +90,6 @@ extern const char * cmd_error(const struct cmd_parser * p);
|
||||||
|
|
||||||
void cmd_parser_close(struct cmd_parser * p);
|
void cmd_parser_close(struct cmd_parser * p);
|
||||||
|
|
||||||
extern int cmd_marshall(buffer * b, uint8_t method);
|
//extern int cmd_marshall(buffer * b, uint8_t method);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,40 +4,31 @@
|
||||||
#include "stm.h"
|
#include "stm.h"
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
|
|
||||||
#define BUFF_SIZE 4096
|
#define BUFF_SIZE 1024
|
||||||
|
|
||||||
struct cmd_st {
|
struct cmd_st {
|
||||||
/** buffer utilizado para I/O */
|
|
||||||
buffer *rb, *wb;
|
buffer *rb, *wb;
|
||||||
struct cmd_parser parser;
|
struct cmd_parser parser;
|
||||||
/** el método de autenticación seleccionado */
|
|
||||||
uint8_t cmd;
|
uint8_t cmd;
|
||||||
/** está verificado */
|
|
||||||
uint8_t verified;
|
uint8_t verified;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
|
||||||
|
char username[STR_SIZE];
|
||||||
|
char password[STR_SIZE];
|
||||||
|
char new_username[STR_SIZE];
|
||||||
|
uint8_t byte;
|
||||||
|
uint16_t value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct config {
|
struct config {
|
||||||
struct sockaddr_storage client_addr;
|
|
||||||
socklen_t client_addr_len;
|
|
||||||
|
|
||||||
/** maquinas de estados */
|
|
||||||
struct state_machine stm;
|
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct cmd_st cmd;
|
struct cmd_st cmd;
|
||||||
} client;
|
} client;
|
||||||
|
|
||||||
// TODO: decidir tamaño del buffer
|
|
||||||
uint8_t raw_buff_a[BUFF_SIZE], raw_buff_b[BUFF_SIZE];
|
uint8_t raw_buff_a[BUFF_SIZE], raw_buff_b[BUFF_SIZE];
|
||||||
buffer read_buffer, write_buffer;
|
buffer read_buffer, write_buffer;
|
||||||
|
|
||||||
unsigned references;
|
|
||||||
|
|
||||||
struct config * next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void config_read(struct selector_key *key);
|
void config_read(struct selector_key *key);
|
||||||
void config_write(struct selector_key *key);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
#ifndef PARSER_H
|
||||||
|
#define PARSER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct parser_event {
|
||||||
|
/** tipo de evento */
|
||||||
|
unsigned type;
|
||||||
|
/** caracteres asociados al evento */
|
||||||
|
uint8_t data[3];
|
||||||
|
/** cantidad de datos en el buffer `data' */
|
||||||
|
uint8_t n;
|
||||||
|
|
||||||
|
/** lista de eventos: si es diferente de null ocurrieron varios eventos */
|
||||||
|
struct parser_event *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** describe una transición entre estados */
|
||||||
|
struct parser_state_transition {
|
||||||
|
/* condición: un caracter o una clase de caracter. Por ej: '\r' */
|
||||||
|
int when;
|
||||||
|
/** descriptor del estado destino cuando se cumple la condición */
|
||||||
|
unsigned dest;
|
||||||
|
/** acción 1 que se ejecuta cuando la condición es verdadera. requerida. */
|
||||||
|
void (*act1)(struct parser_event *ret, const uint8_t c);
|
||||||
|
/** otra acción opcional */
|
||||||
|
void (*act2)(struct parser_event *ret, const uint8_t c);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** predicado para utilizar en `when' que retorna siempre true */
|
||||||
|
static const unsigned ANY = 1 << 9;
|
||||||
|
|
||||||
|
/** declaración completa de una máquina de estados */
|
||||||
|
struct parser_definition {
|
||||||
|
/** cantidad de estados */
|
||||||
|
const unsigned states_count;
|
||||||
|
/** por cada estado, sus transiciones */
|
||||||
|
const struct parser_state_transition **states;
|
||||||
|
/** cantidad de estados por transición */
|
||||||
|
const size_t *states_n;
|
||||||
|
|
||||||
|
/** estado inicial */
|
||||||
|
const unsigned start_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inicializa el parser.
|
||||||
|
*
|
||||||
|
* `classes`: caracterización de cada caracter (256 elementos)
|
||||||
|
*/
|
||||||
|
struct parser * parser_init(const unsigned *classes, const struct parser_definition *def);
|
||||||
|
|
||||||
|
/** destruye el parser */
|
||||||
|
void parser_destroy(struct parser *p);
|
||||||
|
|
||||||
|
/** permite resetear el parser al estado inicial */
|
||||||
|
void parser_reset(struct parser *p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* el usuario alimenta el parser con un caracter, y el parser retorna un evento
|
||||||
|
* de parsing. Los eventos son reusado entre llamadas por lo que si se desea
|
||||||
|
* capturar los datos se debe clonar.
|
||||||
|
*/
|
||||||
|
const struct parser_event * parser_feed(struct parser *p, const uint8_t c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* En caso de la aplicacion no necesite clases caracteres, se
|
||||||
|
* provee dicho arreglo para ser usando en `parser_init'
|
||||||
|
*/
|
||||||
|
const unsigned * parser_no_classes(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef PARSER_UTILS_H
|
||||||
|
#define PARSER_UTILS_H
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
enum string_cmp_event_types {
|
||||||
|
STRING_CMP_MAYEQ,
|
||||||
|
/** hay posibilidades de que el string sea igual */
|
||||||
|
STRING_CMP_EQ,
|
||||||
|
/** NO hay posibilidades de que el string sea igual */
|
||||||
|
STRING_CMP_NEQ,
|
||||||
|
};
|
||||||
|
|
||||||
|
const char * parser_utils_strcmpi_event(const enum string_cmp_event_types type);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Crea un parser que verifica que los caracteres recibidos forment el texto
|
||||||
|
* descrito por `s'.
|
||||||
|
*
|
||||||
|
* Si se recibe el evento `STRING_CMP_NEQ' el texto entrado no matchea.
|
||||||
|
*/
|
||||||
|
struct parser_definition parser_utils_strcmpi(const char *s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libera recursos asociado a una llamada de `parser_utils_strcmpi'
|
||||||
|
*/
|
||||||
|
void parser_utils_strcmpi_destroy(const struct parser_definition *p);
|
||||||
|
|
||||||
|
#endif
|
|
@ -3,6 +3,10 @@
|
||||||
|
|
||||||
int findUser(char * username);
|
int findUser(char * username);
|
||||||
|
|
||||||
int checkPassword(int idx, char * password);
|
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);
|
||||||
|
bool delete_user(char * uname);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,5 +3,9 @@
|
||||||
|
|
||||||
void socksv5_passive_accept(struct selector_key * key);
|
void socksv5_passive_accept(struct selector_key * key);
|
||||||
void socksv5_pool_destroy(void);
|
void socksv5_pool_destroy(void);
|
||||||
|
bool get_auth_status();
|
||||||
|
bool set_auth_status(bool auth_status);
|
||||||
|
bool get_pass_dissector_status();
|
||||||
|
bool set_pass_dissector_status(bool pwd_dissector_status);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
14
src/args.c
14
src/args.c
|
@ -21,7 +21,7 @@ static unsigned short port(const char *s) {
|
||||||
return (unsigned short) sl;
|
return (unsigned short) sl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void user(char * s, struct users * user) {
|
static void user(char * s, user_t * user) {
|
||||||
char *p = strchr(s, ':');
|
char *p = strchr(s, ':');
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
fprintf(stderr, "Password not found\n");
|
fprintf(stderr, "Password not found\n");
|
||||||
|
@ -29,8 +29,12 @@ static void user(char * s, struct users * user) {
|
||||||
} else {
|
} else {
|
||||||
*p = 0;
|
*p = 0;
|
||||||
p++;
|
p++;
|
||||||
user->name = s;
|
char * uname = malloc(strlen(s) + 1);
|
||||||
user->pass = p;
|
strcpy(uname, s);
|
||||||
|
char * pass = malloc(strlen(p) + 1);
|
||||||
|
strcpy(pass, p);
|
||||||
|
user->name = uname;
|
||||||
|
user->pass = pass;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +65,7 @@ void parse_args(const int argc, char ** argv, struct socks5args * args) {
|
||||||
args->mng_addr = "127.0.0.1";
|
args->mng_addr = "127.0.0.1";
|
||||||
args->mng_port = 8080;
|
args->mng_port = 8080;
|
||||||
|
|
||||||
args->disectors_enabled = true;
|
args->dissector_enabled = true;
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
int nusers = 0;
|
int nusers = 0;
|
||||||
|
@ -82,7 +86,7 @@ void parse_args(const int argc, char ** argv, struct socks5args * args) {
|
||||||
args->mng_addr = optarg;
|
args->mng_addr = optarg;
|
||||||
break;
|
break;
|
||||||
case 'N':
|
case 'N':
|
||||||
args->disectors_enabled = false;
|
args->dissector_enabled = false;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
args->socks_port = port(optarg);
|
args->socks_port = port(optarg);
|
||||||
|
|
102
src/client.c
102
src/client.c
|
@ -15,6 +15,8 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
#define MAX_SIZE 524
|
#define MAX_SIZE 524
|
||||||
#define MAX_RECV_SIZE 1024
|
#define MAX_RECV_SIZE 1024
|
||||||
#define N(x) (sizeof(x)/sizeof((x)[0]))
|
#define N(x) (sizeof(x)/sizeof((x)[0]))
|
||||||
|
@ -50,7 +52,8 @@ static void usage(const char *progname) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_args(int argc, char ** argv, uint8_t * buffer) {
|
// aceptar -L
|
||||||
|
uint8_t parse_args(int argc, char ** argv, uint8_t * buffer) {
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
if (argc <= 1 || argv[1][0] == '-') {
|
if (argc <= 1 || argv[1][0] == '-') {
|
||||||
|
@ -75,12 +78,15 @@ void parse_args(int argc, char ** argv, uint8_t * buffer) {
|
||||||
argv[i] = argv[i+1];
|
argv[i] = argv[i+1];
|
||||||
argc--;
|
argc--;
|
||||||
|
|
||||||
c = getopt(argc, argv, "hmbtfsazrB:T:l:u:c:p:n:d:S:A:Z:");
|
c = getopt(argc, argv, "hmbtfsazrB:T:l:u:c:A:S:p:n:d:Z:");
|
||||||
// retorna : o ? si le falta el argumento
|
// retorna : o ? si le falta el argumento
|
||||||
if (c == -1)
|
if (c == -1) {
|
||||||
return;
|
fprintf(stderr, "One option required\n");
|
||||||
|
exit(EXIT_FAILURE); // TODO: chequear bien
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
if (optind > 3 || argc == 2) {
|
if (optind < 3 && argc > 2) {
|
||||||
fprintf(stderr, "Only one option allowed\n");
|
fprintf(stderr, "Only one option allowed\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -200,16 +206,73 @@ void parse_args(int argc, char ** argv, uint8_t * buffer) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (optind < argc + 1) {
|
return buffer[9];
|
||||||
// fprintf(stderr, "Argument not accepted: ");
|
|
||||||
// while (optind < argc) {
|
|
||||||
// fprintf(stderr, "%s ", argv[optind++]);
|
|
||||||
// }
|
|
||||||
// fprintf(stderr, "\n");
|
|
||||||
// exit(1);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void parse_response(char * buffer, uint8_t cmd) {
|
||||||
|
if (buffer[0] != 0x01) {
|
||||||
|
fprintf(stderr, "Incorrect response version.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (buffer[1]) {
|
||||||
|
case RESPONSE_OK:
|
||||||
|
fprintf(stdout, "Success.\n");
|
||||||
|
switch (cmd) {
|
||||||
|
case CMD_GET_METRICS:
|
||||||
|
fprintf(stdout, "Metrics: ...\n");
|
||||||
|
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];
|
||||||
|
break;
|
||||||
|
case CMD_LIST_USERS:
|
||||||
|
fprintf(stdout, "Users... \n");
|
||||||
|
break;
|
||||||
|
case CMD_GET_USER_LAST_CONNECTION:
|
||||||
|
fprintf(stdout, "Users... \n");
|
||||||
|
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_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:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RESPONSE_INVALID_TOKEN:
|
||||||
|
fprintf(stdout, "Invalid token.\n");
|
||||||
|
break;
|
||||||
|
case RESPONSE_CMD_NOT_SUPPORTED:
|
||||||
|
fprintf(stdout, "Command not supported.\n");
|
||||||
|
break;
|
||||||
|
case RESPONSE_VERSION_NOT_SUPPORTED:
|
||||||
|
fprintf(stdout, "Version not supported.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const char *err_msg = NULL;
|
const char *err_msg = NULL;
|
||||||
|
@ -232,13 +295,8 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t buffer[MAX_SIZE] = {0};
|
uint8_t buffer[MAX_SIZE] = {0};
|
||||||
parse_args(argc, argv, buffer);
|
uint8_t cmd = parse_args(argc, argv, buffer);
|
||||||
for (int i = 0; i < 100; i++) {
|
|
||||||
fprintf(stderr, "%x ", buffer[i]);
|
|
||||||
}
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
|
|
||||||
|
|
||||||
ssize_t sent = sendto(client, buffer, N(buffer), 0, NULL, sizeof(addr));
|
ssize_t sent = sendto(client, buffer, N(buffer), 0, NULL, sizeof(addr));
|
||||||
if (sent < 0) {
|
if (sent < 0) {
|
||||||
err_msg = "Unable to send cmd";
|
err_msg = "Unable to send cmd";
|
||||||
|
@ -251,8 +309,10 @@ int main(int argc, char **argv) {
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%s\n", recv_buffer);
|
recv_buffer[received] = 0;
|
||||||
|
parse_response(recv_buffer, cmd);
|
||||||
|
// printf("%s\n", recv_buffer);
|
||||||
|
// TODO cambiar la forma en la que imprimimos
|
||||||
err_msg = NULL;
|
err_msg = NULL;
|
||||||
|
|
||||||
int ret = EXIT_SUCCESS;
|
int ret = EXIT_SUCCESS;
|
||||||
|
|
44
src/cmd.c
44
src/cmd.c
|
@ -22,27 +22,24 @@ enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b) {
|
||||||
p->remaining = 8;
|
p->remaining = 8;
|
||||||
break;
|
break;
|
||||||
case cmd_token:
|
case cmd_token:
|
||||||
p->remaining--;
|
|
||||||
p->token <<= 8;
|
p->token <<= 8;
|
||||||
p->token += b;
|
p->token += b;
|
||||||
|
p->remaining--;
|
||||||
if (p->remaining == 0) {
|
if (p->remaining == 0) {
|
||||||
p->state = cmd_cmd;
|
p->state = cmd_cmd;
|
||||||
p->on_token(p, p->token);
|
p->on_token(p, p->token);
|
||||||
fprintf(stderr, "test token hay magia acá\n");
|
|
||||||
fprintf(stderr, "token: %lx\n", p->token);
|
|
||||||
fprintf(stderr, "%d : %d\n", p->state, cmd_cmd);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case cmd_cmd:
|
case cmd_cmd:
|
||||||
if (NULL != p->on_cmd) {
|
if (NULL != p->on_cmd) {
|
||||||
p->on_cmd(p, b); // cambia el state, param_state y remaining
|
p->state = cmd_done;
|
||||||
|
p->on_cmd(p, b);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case cmd_parameters:
|
case cmd_parameters:
|
||||||
switch (p->param_state) {
|
switch (p->param_state) {
|
||||||
case param_ulen:
|
case param_ulen:
|
||||||
p->remaining = b;
|
p->remaining = b;
|
||||||
fprintf(stderr, "ulen: %d\n", p->remaining);
|
|
||||||
p->param_state = param_uname;
|
p->param_state = param_uname;
|
||||||
break;
|
break;
|
||||||
case param_uname:
|
case param_uname:
|
||||||
|
@ -50,7 +47,6 @@ enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b) {
|
||||||
p->remaining--;
|
p->remaining--;
|
||||||
if (p->remaining == 0) {
|
if (p->remaining == 0) {
|
||||||
*(p->username + p->idx++) = 0;
|
*(p->username + p->idx++) = 0;
|
||||||
fprintf(stderr, "old_uname: %s\n", 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->cmd == CMD_GET_USER_LAST_CONNECTION)
|
||||||
|
@ -76,7 +72,7 @@ enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case param_byte:
|
case param_byte:
|
||||||
p->byte = b;
|
*p->byte = b;
|
||||||
p->state = cmd_done;
|
p->state = cmd_done;
|
||||||
break;
|
break;
|
||||||
case param_new_ulen:
|
case param_new_ulen:
|
||||||
|
@ -89,13 +85,14 @@ enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b) {
|
||||||
|
|
||||||
if (p->remaining == 0) {
|
if (p->remaining == 0) {
|
||||||
*(p->new_username + p->idx++) = 0;
|
*(p->new_username + p->idx++) = 0;
|
||||||
fprintf(stderr, "new_uname: %s", p->new_username);
|
|
||||||
p->idx = 0;
|
p->idx = 0;
|
||||||
p->state = cmd_done;
|
p->state = cmd_done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case param_value:
|
case param_value:
|
||||||
p->token += (uint16_t) (b * pow(255, --p->remaining));
|
*p->value <<= 8;
|
||||||
|
*p->value += b;
|
||||||
|
p->remaining--;
|
||||||
if (p->remaining == 0) {
|
if (p->remaining == 0) {
|
||||||
p->state = cmd_done;
|
p->state = cmd_done;
|
||||||
}
|
}
|
||||||
|
@ -110,7 +107,6 @@ enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b) {
|
||||||
fprintf(stderr, "unknown state %d\n", p->state);
|
fprintf(stderr, "unknown state %d\n", p->state);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
return p->state;
|
return p->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,16 +166,16 @@ extern enum cmd_state cmd_consume(buffer * b, struct cmd_parser * p, bool * erro
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int cmd_marshall(buffer * b, const uint8_t status) {
|
//extern int cmd_marshall(buffer * b, const uint8_t status) {
|
||||||
size_t n;
|
// size_t n;
|
||||||
uint8_t * buff = buffer_write_ptr(b, &n);
|
// uint8_t * buff = buffer_write_ptr(b, &n);
|
||||||
if (n < 2) {
|
// if (n < 2) {
|
||||||
return -1;
|
// return -1;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
buff[0] = 0x01;
|
// buff[0] = 0x01;
|
||||||
buff[1] = status;
|
// buff[1] = status;
|
||||||
|
//
|
||||||
buffer_write_adv(b, 2);
|
// buffer_write_adv(b, 2);
|
||||||
return 2;
|
// return 2;
|
||||||
}
|
//}
|
||||||
|
|
187
src/confignio.c
187
src/confignio.c
|
@ -3,23 +3,19 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include "selector.h"
|
#include "selector.h"
|
||||||
#include "confignio.h"
|
#include "confignio.h"
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
|
#include "server.h"
|
||||||
|
#include "socks5nio.h"
|
||||||
|
|
||||||
#define N(x) (sizeof(x)/sizeof((x)[0]))
|
#define N(x) (sizeof(x)/sizeof((x)[0]))
|
||||||
|
|
||||||
#define TOKEN 0x0FF1CEDEADB00B1E
|
#define TOKEN 0x0FF1CEDEADB00B1E
|
||||||
|
|
||||||
//enum config_state {
|
|
||||||
// READ,
|
|
||||||
// WRITE,
|
|
||||||
// DONE,
|
|
||||||
// ERROR,
|
|
||||||
//};
|
|
||||||
|
|
||||||
static void on_token(struct cmd_parser * p, const uint64_t token) {
|
static void on_token(struct cmd_parser * p, const uint64_t token) {
|
||||||
*p->verified = (token - (uint64_t) TOKEN == 0);
|
*p->verified = (token - (uint64_t) TOKEN == 0);
|
||||||
p->state = cmd_cmd;
|
p->state = cmd_cmd;
|
||||||
|
@ -31,116 +27,113 @@ static void on_cmd(struct cmd_parser * p, const uint8_t cmd) {
|
||||||
uint8_t * selected = p->cmd;
|
uint8_t * selected = p->cmd;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case CMD_GET_METRICS:
|
case CMD_GET_METRICS:
|
||||||
* selected = CMD_GET_METRICS;
|
*selected = CMD_GET_METRICS;
|
||||||
break;
|
break;
|
||||||
case CMD_GET_BUFFER_SIZE:
|
case CMD_GET_BUFFER_SIZE:
|
||||||
* selected = CMD_GET_BUFFER_SIZE;
|
*selected = CMD_GET_BUFFER_SIZE;
|
||||||
break;
|
break;
|
||||||
case CMD_SET_BUFFER_SIZE:
|
case CMD_SET_BUFFER_SIZE:
|
||||||
* selected = CMD_SET_BUFFER_SIZE;
|
*selected = CMD_SET_BUFFER_SIZE;
|
||||||
p->state = cmd_parameters;
|
p->state = cmd_parameters;
|
||||||
p->remaining = 2;
|
p->remaining = 2;
|
||||||
p->param_state = param_value;
|
p->param_state = param_value;
|
||||||
break;
|
break;
|
||||||
case CMD_GET_TIMEOUT:
|
case CMD_GET_TIMEOUT:
|
||||||
* selected = CMD_GET_TIMEOUT;
|
*selected = CMD_GET_TIMEOUT;
|
||||||
break;
|
break;
|
||||||
case CMD_SET_TIMEOUT:
|
case CMD_SET_TIMEOUT:
|
||||||
* selected = CMD_SET_TIMEOUT;
|
*selected = CMD_SET_TIMEOUT;
|
||||||
p->state = cmd_parameters;
|
p->state = cmd_parameters;
|
||||||
p->remaining = 2;
|
p->remaining = 2;
|
||||||
p->param_state = param_value;
|
p->param_state = param_value;
|
||||||
break;
|
break;
|
||||||
case CMD_GET_USER_PAGES:
|
case CMD_GET_USER_PAGES:
|
||||||
* selected = CMD_GET_USER_PAGES;
|
*selected = CMD_GET_USER_PAGES;
|
||||||
break;
|
break;
|
||||||
case CMD_LIST_USERS:
|
case CMD_LIST_USERS:
|
||||||
* selected = CMD_LIST_USERS;
|
*selected = CMD_LIST_USERS;
|
||||||
p->state = cmd_parameters;
|
p->state = cmd_parameters;
|
||||||
p->param_state = param_byte;
|
p->param_state = param_byte;
|
||||||
p->remaining = 1;
|
p->remaining = 1;
|
||||||
break;
|
break;
|
||||||
case CMD_GET_USER_LAST_CONNECTION:
|
case CMD_GET_USER_LAST_CONNECTION:
|
||||||
* selected = CMD_GET_USER_LAST_CONNECTION;
|
*selected = CMD_GET_USER_LAST_CONNECTION;
|
||||||
p->state = cmd_parameters;
|
p->state = cmd_parameters;
|
||||||
p->param_state = param_ulen;
|
p->param_state = param_ulen;
|
||||||
p->remaining = 1;
|
p->remaining = 1;
|
||||||
break;
|
break;
|
||||||
case CMD_MODIFY_USERNAME:
|
case CMD_MODIFY_USERNAME:
|
||||||
* selected = CMD_MODIFY_USERNAME;
|
*selected = CMD_MODIFY_USERNAME;
|
||||||
p->state = cmd_parameters;
|
p->state = cmd_parameters;
|
||||||
p->param_state = param_ulen;
|
p->param_state = param_ulen;
|
||||||
p->remaining = 1;
|
p->remaining = 1;
|
||||||
break;
|
break;
|
||||||
case CMD_MODIFY_PASSWORD:
|
case CMD_MODIFY_PASSWORD:
|
||||||
* selected = CMD_MODIFY_PASSWORD;
|
*selected = CMD_MODIFY_PASSWORD;
|
||||||
p->state = cmd_parameters;
|
p->state = cmd_parameters;
|
||||||
p->param_state = param_ulen;
|
p->param_state = param_ulen;
|
||||||
p->remaining = 1;
|
p->remaining = 1;
|
||||||
break;
|
break;
|
||||||
case CMD_ADD_USER:
|
case CMD_ADD_USER:
|
||||||
* selected = CMD_ADD_USER;
|
*selected = CMD_ADD_USER;
|
||||||
p->state = cmd_parameters;
|
p->state = cmd_parameters;
|
||||||
p->param_state = param_ulen;
|
p->param_state = param_ulen;
|
||||||
p->remaining = 1;
|
p->remaining = 1;
|
||||||
break;
|
break;
|
||||||
case CMD_DELETE_USER:
|
case CMD_DELETE_USER:
|
||||||
* selected = CMD_DELETE_USER ;
|
*selected = CMD_DELETE_USER ;
|
||||||
p->state = cmd_parameters;
|
p->state = cmd_parameters;
|
||||||
p->param_state = param_ulen;
|
p->param_state = param_ulen;
|
||||||
p->remaining = 1;
|
p->remaining = 1;
|
||||||
break;
|
break;
|
||||||
case CMD_GET_PASSWORD_DISSECTOR_STATUS:
|
case CMD_GET_PASSWORD_DISSECTOR_STATUS:
|
||||||
* selected = CMD_GET_PASSWORD_DISSECTOR_STATUS;
|
*selected = CMD_GET_PASSWORD_DISSECTOR_STATUS;
|
||||||
break;
|
break;
|
||||||
case CMD_MODIFY_PASSWORD_DISSECTOR_STATUS:
|
case CMD_MODIFY_PASSWORD_DISSECTOR_STATUS:
|
||||||
* selected = CMD_MODIFY_PASSWORD_DISSECTOR_STATUS;
|
*selected = CMD_MODIFY_PASSWORD_DISSECTOR_STATUS;
|
||||||
* selected = CMD_LIST_USERS;
|
|
||||||
p->state = cmd_parameters;
|
p->state = cmd_parameters;
|
||||||
p->param_state = param_byte;
|
p->param_state = param_byte;
|
||||||
p->remaining = 1;
|
p->remaining = 1;
|
||||||
break;
|
break;
|
||||||
case CMD_GET_AUTHENTICATION_STATUS:
|
case CMD_GET_AUTHENTICATION_STATUS:
|
||||||
* selected = CMD_GET_AUTHENTICATION_STATUS;
|
*selected = CMD_GET_AUTHENTICATION_STATUS;
|
||||||
break;
|
break;
|
||||||
case CMD_MODIFY_AUTHENTICATION_STATUS:
|
case CMD_MODIFY_AUTHENTICATION_STATUS:
|
||||||
* selected = CMD_MODIFY_AUTHENTICATION_STATUS;
|
*selected = CMD_MODIFY_AUTHENTICATION_STATUS;
|
||||||
* selected = CMD_LIST_USERS;
|
|
||||||
p->state = cmd_parameters;
|
p->state = cmd_parameters;
|
||||||
p->param_state = param_byte;
|
p->param_state = param_byte;
|
||||||
p->remaining = 1;
|
p->remaining = 1;
|
||||||
break;
|
break;
|
||||||
case CMD_GET_PROXY_SERVER_STATUS:
|
case CMD_GET_PROXY_SERVER_STATUS:
|
||||||
* selected = CMD_GET_PROXY_SERVER_STATUS;
|
*selected = CMD_GET_PROXY_SERVER_STATUS;
|
||||||
break;
|
break;
|
||||||
case CMD_CHANGE_PROXY_SERVER_STATUS:
|
case CMD_CHANGE_PROXY_SERVER_STATUS:
|
||||||
* selected = CMD_CHANGE_PROXY_SERVER_STATUS;
|
*selected = CMD_CHANGE_PROXY_SERVER_STATUS;
|
||||||
* selected = CMD_LIST_USERS;
|
|
||||||
p->state = cmd_parameters;
|
p->state = cmd_parameters;
|
||||||
p->param_state = param_byte;
|
p->param_state = param_byte;
|
||||||
p->remaining = 1;
|
p->remaining = 1;
|
||||||
break;
|
break;
|
||||||
case CMD_RESTART_PROXY_SERVER:
|
case CMD_RESTART_PROXY_SERVER:
|
||||||
* selected = CMD_RESTART_PROXY_SERVER;
|
*selected = CMD_RESTART_PROXY_SERVER;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
* selected = CMD_NOT_SUPPORTED_CMD;
|
*selected = CMD_NOT_SUPPORTED_CMD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_process(struct cmd_st * d) {
|
//void cmd_process(struct cmd_st * d) {
|
||||||
// unsigned ret = WRITE;
|
//// 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;
|
||||||
|
//}
|
||||||
|
|
||||||
uint8_t m = d->status;
|
#define ATTACHMENT(key) ((struct config *)(key)->data)
|
||||||
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) {
|
static void config_read_init(struct selector_key * key) {
|
||||||
struct cmd_st *d = &ATTACHMENT(key)->client.cmd;
|
struct cmd_st *d = &ATTACHMENT(key)->client.cmd;
|
||||||
|
@ -152,9 +145,100 @@ static void config_read_init(struct selector_key * key) {
|
||||||
d->parser.on_cmd = on_cmd;
|
d->parser.on_cmd = on_cmd;
|
||||||
d->parser.on_token = on_token;
|
d->parser.on_token = on_token;
|
||||||
d->parser.idx = 0;
|
d->parser.idx = 0;
|
||||||
|
|
||||||
|
d->parser.username = d->username;
|
||||||
|
d->parser.password = d->password;
|
||||||
|
d->parser.byte = &d->byte;
|
||||||
|
d->parser.value = &d->value;
|
||||||
|
d->parser.new_username = d->new_username;
|
||||||
cmd_parser_init(&d->parser);
|
cmd_parser_init(&d->parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t cmd_process(struct selector_key *key, buffer * b) {
|
||||||
|
struct cmd_st *d = &ATTACHMENT(key)->client.cmd;
|
||||||
|
|
||||||
|
size_t n;
|
||||||
|
uint8_t *buff = buffer_write_ptr(b, &n);
|
||||||
|
|
||||||
|
if (n < 2) {
|
||||||
|
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) {
|
||||||
|
buff[i++] = d->status;
|
||||||
|
buffer_write_adv(b, i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
buff[i++] = 0x00;
|
||||||
|
switch (d->cmd) {
|
||||||
|
case CMD_GET_METRICS:
|
||||||
|
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:
|
||||||
|
break;
|
||||||
|
case CMD_LIST_USERS:
|
||||||
|
break;
|
||||||
|
case CMD_GET_USER_LAST_CONNECTION:
|
||||||
|
break;
|
||||||
|
case CMD_MODIFY_USERNAME:
|
||||||
|
status = modify_username(d->username, d->new_username);
|
||||||
|
break;
|
||||||
|
case CMD_MODIFY_PASSWORD:
|
||||||
|
status = modify_password(d->username, d->password);
|
||||||
|
break;
|
||||||
|
case CMD_ADD_USER:
|
||||||
|
status = add_user(d->username, d->password);
|
||||||
|
break;
|
||||||
|
case CMD_DELETE_USER:
|
||||||
|
status = delete_user(d->username);
|
||||||
|
break;
|
||||||
|
case CMD_GET_PASSWORD_DISSECTOR_STATUS:
|
||||||
|
buff[i++] = get_pass_dissector_status();
|
||||||
|
break;
|
||||||
|
case CMD_MODIFY_PASSWORD_DISSECTOR_STATUS:
|
||||||
|
set_pass_dissector_status(d->byte);
|
||||||
|
break;
|
||||||
|
case CMD_GET_AUTHENTICATION_STATUS:
|
||||||
|
buff[i++] = get_auth_status();
|
||||||
|
break;
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_write_adv(b, i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: manejo de errores
|
||||||
void config_read(struct selector_key *key) {
|
void config_read(struct selector_key *key) {
|
||||||
struct cmd_st *d = &ATTACHMENT(key)->client.cmd;
|
struct cmd_st *d = &ATTACHMENT(key)->client.cmd;
|
||||||
bool error = false;
|
bool error = false;
|
||||||
|
@ -171,9 +255,10 @@ void config_read(struct selector_key *key) {
|
||||||
buffer_write_adv(d->rb, n);
|
buffer_write_adv(d->rb, n);
|
||||||
const enum cmd_state st = cmd_consume(d->rb, &d->parser, &error);
|
const enum cmd_state st = cmd_consume(d->rb, &d->parser, &error);
|
||||||
|
|
||||||
if (cmd_is_done(st, 0)) {
|
if (cmd_is_done(st, &error)) {
|
||||||
if (SELECTOR_SUCCESS == selector_set_interest_key(key, OP_WRITE)) {
|
if (SELECTOR_SUCCESS == selector_set_interest_key(key, OP_WRITE)) {
|
||||||
cmd_process(d);
|
if (cmd_process(key, d->wb) == 0)
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -181,18 +266,9 @@ void config_read(struct selector_key *key) {
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void config_write(struct selector_key *key) {
|
|
||||||
struct cmd_st *d = &ATTACHMENT(key)->client.cmd;
|
|
||||||
uint8_t *ptr;
|
|
||||||
size_t count;
|
|
||||||
ssize_t n;
|
|
||||||
struct sockaddr_storage client_addr;
|
|
||||||
socklen_t client_addr_len = sizeof(client_addr);
|
|
||||||
|
|
||||||
ptr = buffer_read_ptr(d->wb, &count);
|
ptr = buffer_read_ptr(d->wb, &count);
|
||||||
n = sendto(key->fd, ptr, count, 0, (struct sockaddr *) &client_addr, sizeof(client_addr_len));
|
n = sendto(key->fd, ptr, count, 0, (struct sockaddr *) &client_addr, sizeof(client_addr));
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -203,4 +279,7 @@ void config_write(struct selector_key *key) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
buffer_reset(d->rb);
|
||||||
|
buffer_reset(d->wb);
|
||||||
|
selector_set_interest_key(key, OP_READ);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
// This is a personal academic project. Dear PVS-Studio, please check it.
|
||||||
|
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
/* CDT del parser */
|
||||||
|
struct parser {
|
||||||
|
/** tipificación para cada caracter */
|
||||||
|
const unsigned *classes;
|
||||||
|
/** definición de estados */
|
||||||
|
const struct parser_definition *def;
|
||||||
|
|
||||||
|
/* estado actual */
|
||||||
|
unsigned state;
|
||||||
|
|
||||||
|
/* evento que se retorna */
|
||||||
|
struct parser_event e1;
|
||||||
|
/* evento que se retorna */
|
||||||
|
struct parser_event e2;
|
||||||
|
};
|
||||||
|
|
||||||
|
void parser_destroy(struct parser *p) {
|
||||||
|
if (p != NULL) {
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct parser * parser_init(const unsigned *classes, const struct parser_definition *def) {
|
||||||
|
struct parser *ret = malloc(sizeof(*ret));
|
||||||
|
if (ret != NULL) {
|
||||||
|
memset(ret, 0, sizeof(*ret));
|
||||||
|
ret->classes = classes;
|
||||||
|
ret->def = def;
|
||||||
|
ret->state = def->start_state;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parser_reset(struct parser *p) {
|
||||||
|
p->state = p->def->start_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct parser_event * parser_feed(struct parser *p, const uint8_t c) {
|
||||||
|
const unsigned type = p->classes[c];
|
||||||
|
|
||||||
|
p->e1.next = p->e2.next = 0;
|
||||||
|
|
||||||
|
const struct parser_state_transition *state = p->def->states[p->state];
|
||||||
|
const size_t n = p->def->states_n[p->state];
|
||||||
|
bool matched = false;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
matched = true;
|
||||||
|
} else if (state[i].when > 0xFF) {
|
||||||
|
matched = (type & when);
|
||||||
|
} else {
|
||||||
|
matched = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matched) {
|
||||||
|
state[i].act1(&p->e1, c);
|
||||||
|
if (state[i].act2 != NULL) {
|
||||||
|
p->e1.next = &p->e2;
|
||||||
|
state[i].act2(&p->e2, c);
|
||||||
|
}
|
||||||
|
p->state = state[i].dest;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &p->e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const unsigned classes[0xFF] = {0x00};
|
||||||
|
|
||||||
|
const unsigned * parser_no_classes(void) {
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
// This is a personal academic project. Dear PVS-Studio, please check it.
|
||||||
|
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "parser_utils.h"
|
||||||
|
|
||||||
|
const char * parser_utils_strcmpi_event(const enum string_cmp_event_types type) {
|
||||||
|
const char *ret;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case STRING_CMP_MAYEQ:
|
||||||
|
ret = "wait(c)";
|
||||||
|
break;
|
||||||
|
case STRING_CMP_EQ:
|
||||||
|
ret = "eq(c)";
|
||||||
|
break;
|
||||||
|
case STRING_CMP_NEQ:
|
||||||
|
ret = "neq(c)";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void may_eq(struct parser_event *ret, const uint8_t c) {
|
||||||
|
ret->type = STRING_CMP_MAYEQ;
|
||||||
|
ret->n = 1;
|
||||||
|
ret->data[0] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eq(struct parser_event *ret, const uint8_t c) {
|
||||||
|
ret->type = STRING_CMP_EQ;
|
||||||
|
ret->n = 1;
|
||||||
|
ret->data[0] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void neq(struct parser_event *ret, const uint8_t c) {
|
||||||
|
ret->type = STRING_CMP_NEQ;
|
||||||
|
ret->n = 1;
|
||||||
|
ret->data[0] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* para comparar "foo" (length 3) necesitamos 3 + 2 estados.
|
||||||
|
* Los útimos dos, son el sumidero de comparación fallida, y
|
||||||
|
* el estado donde se llegó a la comparación completa.
|
||||||
|
*
|
||||||
|
* static const struct parser_state_transition ST_0 [] = {
|
||||||
|
* {.when = 'F', .dest = 1, .action1 = may_eq, },
|
||||||
|
* {.when = 'f', .dest = 1, .action1 = may_eq, },
|
||||||
|
* {.when = ANY, .dest = NEQ, .action1 = neq,},
|
||||||
|
* };
|
||||||
|
* static const struct parser_state_transition ST_1 [] = {
|
||||||
|
* {.when = 'O', .dest = 2, .action1 = may_eq, },
|
||||||
|
* {.when = 'o', .dest = 2, .action1 = may_eq, },
|
||||||
|
* {.when = ANY, .dest = NEQ, .action1 = neq,},
|
||||||
|
* };
|
||||||
|
* static const struct parser_state_transition ST_2 [] = {
|
||||||
|
* {.when = 'O', .dest = EQ, .action1 = eq, },
|
||||||
|
* {.when = 'o', .dest = EQ, .action1 = eq, },
|
||||||
|
* {.when = ANY, .dest = NEQ, .action1 = neq,},
|
||||||
|
* };
|
||||||
|
* static const struct parser_state_transition ST_EQ (3) [] = {
|
||||||
|
* {.when = ANY, .dest = NEQ, .action1 = neq,},
|
||||||
|
* };
|
||||||
|
* static const struct parser_state_transition ST_NEQ (4) [] = {
|
||||||
|
* {.when = ANY, .dest = NEQ, .action1 = neq,},
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct parser_definition parser_utils_strcmpi(const char *s) {
|
||||||
|
const size_t n = strlen(s);
|
||||||
|
|
||||||
|
struct parser_state_transition **states = calloc(n + 2, sizeof(*states));
|
||||||
|
size_t *nstates = calloc(n + 2, sizeof(*nstates));
|
||||||
|
struct parser_state_transition *transitions = calloc(3 * (n + 2), sizeof(*transitions));
|
||||||
|
|
||||||
|
if (states == NULL || nstates == NULL || transitions == NULL) {
|
||||||
|
free(states);
|
||||||
|
free(nstates);
|
||||||
|
free(transitions);
|
||||||
|
|
||||||
|
struct parser_definition def = {
|
||||||
|
.start_state = 0,
|
||||||
|
.states_count = 0,
|
||||||
|
.states = NULL,
|
||||||
|
.states_n = NULL,
|
||||||
|
};
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
// estados fijos
|
||||||
|
const size_t st_eq = n;
|
||||||
|
const size_t st_neq = n + 1;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < n; i++) {
|
||||||
|
const size_t dest = (i + 1 == n) ? st_eq : i + 1;
|
||||||
|
|
||||||
|
transitions[i * 3 + 0].when = tolower(s[i]);
|
||||||
|
transitions[i * 3 + 0].dest = dest;
|
||||||
|
transitions[i * 3 + 0].act1 = i + 1 == n ? eq : may_eq;
|
||||||
|
transitions[i * 3 + 1].when = toupper(s[i]);
|
||||||
|
transitions[i * 3 + 1].dest = dest;
|
||||||
|
transitions[i * 3 + 1].act1 = i + 1 == n ? eq : may_eq;
|
||||||
|
transitions[i * 3 + 2].when = ANY;
|
||||||
|
transitions[i * 3 + 2].dest = st_neq;
|
||||||
|
transitions[i * 3 + 2].act1 = neq;
|
||||||
|
states[i] = transitions + (i * 3 + 0);
|
||||||
|
nstates[i] = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// EQ
|
||||||
|
transitions[(n + 0) * 3].when = ANY;
|
||||||
|
transitions[(n + 0) * 3].dest = st_neq;
|
||||||
|
transitions[(n + 0) * 3].act1 = neq;
|
||||||
|
states[(n + 0)] = transitions + ((n + 0) * 3 + 0);
|
||||||
|
nstates[(n + 0)] = 1;
|
||||||
|
|
||||||
|
// NEQ
|
||||||
|
transitions[(n + 1) * 3].when = ANY;
|
||||||
|
transitions[(n + 1) * 3].dest = st_neq;
|
||||||
|
transitions[(n + 1) * 3].act1 = neq;
|
||||||
|
states[(n + 1)] = transitions + ((n + 1) * 3 + 0);
|
||||||
|
nstates[(n + 1)] = 1;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parser_utils_strcmpi_destroy(const struct parser_definition *p) {
|
||||||
|
free((void *)p->states[0]);
|
||||||
|
free((void *)p->states);
|
||||||
|
free((void *)p->states_n);
|
||||||
|
}
|
|
@ -97,7 +97,6 @@ static enum request_state dstaddr(const uint8_t c, struct request_parser * p) {
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
static enum request_state dstport(const uint8_t c, struct request_parser * p) {
|
static enum request_state dstport(const uint8_t c, struct request_parser * p) {
|
||||||
enum request_state next;
|
enum request_state next;
|
||||||
|
|
48
src/server.c
48
src/server.c
|
@ -160,7 +160,7 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
const struct fd_handler config = {
|
const struct fd_handler config = {
|
||||||
.handle_read = config_read,
|
.handle_read = config_read,
|
||||||
.handle_write = config_write,
|
.handle_write = NULL,
|
||||||
.handle_close = NULL,
|
.handle_close = NULL,
|
||||||
};
|
};
|
||||||
ss = selector_register(selector, udp_server, &config, OP_READ, config_ret);
|
ss = selector_register(selector, udp_server, &config, OP_READ, config_ret);
|
||||||
|
@ -214,6 +214,50 @@ int findUser(char * username) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int checkPassword(int idx, char * password) {
|
int check_password(int idx, char * password) {
|
||||||
return !strcmp(args->users[idx].pass, password);
|
return !strcmp(args->users[idx].pass, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool add_user(char * username, char * password) {
|
||||||
|
if (args->nusers < MAX_USERS) {
|
||||||
|
user_t * user = malloc(sizeof(user_t));
|
||||||
|
user->name = malloc(strlen(username));
|
||||||
|
strcpy(user->name, username);
|
||||||
|
user->pass = malloc(strlen(password));
|
||||||
|
strcpy(user->pass, password);
|
||||||
|
args->users[args->nusers] = *user;
|
||||||
|
args->nusers++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool 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));
|
||||||
|
strcpy(args->users[idx].name, new_uname);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool 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));
|
||||||
|
strcpy(args->users[idx].pass, new_pwd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool delete_user(char * uname) {
|
||||||
|
int idx = findUser(uname);
|
||||||
|
if (idx == -1)
|
||||||
|
return false;
|
||||||
|
free(args->users[idx].name);
|
||||||
|
free(args->users[idx].pass);
|
||||||
|
for (int i = idx; i < args->nusers; i++) {
|
||||||
|
args->users[i] = args->users[i+1];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,14 @@
|
||||||
#define BUFF_SIZE 4096 // TODO: decidir tamaño del buffer (2048 muy lento para archivos grandes!!!)
|
#define BUFF_SIZE 4096 // TODO: decidir tamaño del buffer (2048 muy lento para archivos grandes!!!)
|
||||||
|
|
||||||
// TODO: hacer que cambie con nuestro proto
|
// TODO: hacer que cambie con nuestro proto
|
||||||
int auth_active = 1;
|
bool auth_active = true;
|
||||||
|
bool pwd_dissector_active = false;
|
||||||
|
|
||||||
|
int total_connect = 0;
|
||||||
|
int now_connect = 0;
|
||||||
|
long long bytes_transferred = 0;
|
||||||
|
int buff_size = 4096;
|
||||||
|
int timeout = 10;
|
||||||
|
|
||||||
/** maquina de estados general */
|
/** maquina de estados general */
|
||||||
enum socks_v5state {
|
enum socks_v5state {
|
||||||
|
@ -46,6 +53,26 @@ enum socks_v5state {
|
||||||
ERROR,
|
ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool get_auth_status() {
|
||||||
|
return auth_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_auth_status(bool auth_status) {
|
||||||
|
auth_active = auth_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_pass_dissector_status() {
|
||||||
|
return pwd_dissector_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_pass_dissector_status(bool pwd_dissector_status) {
|
||||||
|
pwd_dissector_active = pwd_dissector_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long get_bytes_transferred() {
|
||||||
|
return bytes_transferred;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Definición de variables para cada estado
|
// Definición de variables para cada estado
|
||||||
|
|
||||||
|
@ -408,7 +435,7 @@ static void on_auth_username(struct auth_parser * p, char * username) {
|
||||||
/** callback del parser utilizado en `read_auth' */
|
/** callback del parser utilizado en `read_auth' */
|
||||||
static void on_auth_password(struct auth_parser * p, char * password) {
|
static void on_auth_password(struct auth_parser * p, char * password) {
|
||||||
uint8_t * verified = p->verified;
|
uint8_t * verified = p->verified;
|
||||||
if (checkPassword(p->user_pos, password))
|
if (check_password(p->user_pos, password))
|
||||||
* verified = 1;
|
* verified = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -747,7 +774,22 @@ static unsigned request_connecting(struct selector_key * key) {
|
||||||
return SELECTOR_SUCCESS == s ? REQUEST_WRITE : ERROR;
|
return SELECTOR_SUCCESS == s ? REQUEST_WRITE : ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// void log_request(enum socks_response_status status, const struct sockaddr * clientaddr, const struct sockaddr * originaddr);
|
void log_request(enum socks_response_status status, const struct sockaddr * client_addr, const struct sockaddr * origin_addr) {
|
||||||
|
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));
|
||||||
|
size_t len = strlen(cbuff);
|
||||||
|
sockaddr_to_human(cbuff + len, N(cbuff) - len, client_addr);
|
||||||
|
strncat(cbuff, "\t", 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);
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned request_write(struct selector_key * key) {
|
static unsigned request_write(struct selector_key * key) {
|
||||||
struct request_st * d = &ATTACHMENT(key)->client.request;
|
struct request_st * d = &ATTACHMENT(key)->client.request;
|
||||||
|
@ -780,7 +822,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(d->status, (const struct sockaddr *) &ATTACHMENT(key)->client_addr, (const struct sockaddr *) &ATTACHMENT(key)->origin_addr);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,8 +844,6 @@ static void copy_init(const unsigned state, struct selector_key * key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned copy_compute_interests(fd_selector s, struct copy * d) {
|
static unsigned copy_compute_interests(fd_selector s, struct copy * d) {
|
||||||
// ... TODO ...
|
|
||||||
|
|
||||||
fd_interest ret = OP_NOOP;
|
fd_interest ret = OP_NOOP;
|
||||||
if ((d->duplex & OP_READ) && buffer_can_write(d->rb)) {
|
if ((d->duplex & OP_READ) && buffer_can_write(d->rb)) {
|
||||||
ret |= OP_READ;
|
ret |= OP_READ;
|
||||||
|
@ -876,6 +916,7 @@ static unsigned copy_w(struct selector_key * key) {
|
||||||
d->other->duplex &= ~OP_READ;
|
d->other->duplex &= ~OP_READ;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
bytes_transferred += n;
|
||||||
buffer_read_adv(b, n);
|
buffer_read_adv(b, n);
|
||||||
}
|
}
|
||||||
copy_compute_interests(key->s, d);
|
copy_compute_interests(key->s, d);
|
||||||
|
|
Loading…
Reference in New Issue