Compare commits

...

27 Commits

Author SHA1 Message Date
22f7df1524 Added error checking for return value from 'easysock' functions 2023-04-04 22:44:10 -05:00
4d606df24d Updated easysock library files 2023-04-04 22:43:52 -05:00
69da015727 Removed testing code, fixed bug where domain didn't translate correctly to address 2023-03-08 19:19:35 -06:00
1ab6ffe44f Added code for testing 2023-03-08 19:10:25 -06:00
66150609c3 Added 'inet_to_int' function, and 'char_to_socktype' function; started working on domain name support for remote address 2023-03-08 16:07:06 -06:00
25bbcb620e Added inet_to_int function 2023-03-08 15:45:47 -06:00
2e5d2e64c0 Removed check for IP version in remote address 2023-03-08 15:45:16 -06:00
ec3698c14a Added 'char_to_socktype' function 2023-03-08 11:29:04 -06:00
7a09e7188c Added int_to_inet function 2023-03-08 11:11:08 -06:00
5261398d69 Moved 'check_ip_ver' function to easysock.c 2023-03-08 11:08:33 -06:00
d8ef471618 Updated README 2023-03-03 09:21:35 -06:00
9c1e447dbe Replaced exit codes with values that aren't taken by errno 2023-03-03 09:21:13 -06:00
35398d8387 Added 'PROG_VER' constant, added '--version' and '--help' flags 2023-02-26 12:28:59 -06:00
dc44f4979c Fixed comment accuracy regarding error codes 2023-02-25 21:30:39 -06:00
d1f34083bf Replaced negative exit codes with positive ones or 'errno' 2023-02-25 21:29:17 -06:00
4c49370276 Added check for number of arguments 2023-02-25 21:28:50 -06:00
e483ffaf8f Replaced negative exit codes with positive ones or 'errno' 2023-02-25 21:27:48 -06:00
a157fd5851 Updated TODO.txt 2023-02-24 22:21:48 -06:00
ca1cb08cd9 Fixed indendation issues 2023-02-24 22:19:56 -06:00
f0d084ad9d Added check for IPv6, updated calls to 'create_remote' to include new paramter 2023-02-24 22:18:04 -06:00
130346b006 Added new paramter to 'create_remote' function, fixed minor bugs 2023-02-24 22:09:41 -06:00
dbc838aa50 Updated definition for 'create_remote' function 2023-02-24 22:06:54 -06:00
a321f677a4 Added 'debug' target 2023-02-24 22:01:35 -06:00
de79fc1ff7 Fixed spelling mistake 2023-02-24 19:57:48 -06:00
2ac2bf7249 Updated TODO.txt 2023-02-24 12:45:18 -06:00
0b9a8ef292 Replaced 'printf' with 'exit(errno)' to make the functions portable 2023-02-24 12:40:59 -06:00
a56bda12b5 Updated TODO.txt 2023-02-24 12:40:01 -06:00
6 changed files with 192 additions and 68 deletions

View File

@@ -8,6 +8,9 @@ $(EXEC_FILE): main.o easysock.o
allwarn: CFLAGS+=-Wall -Wextra -pedantic
allwarn: $(EXEC_FILE)
debug: CFLAGS+=-g
debug: $(EXEC_FILE)
clean: $(EXEC_FILE) main.o easysock.o
rm ./$(EXEC_FILE)

View File

@@ -10,3 +10,4 @@ TODO
## Usage
./proxy <local-address> <local-port> <remote-address> <remote-port>
### If the program doesn't work, check the errno. Run 'errno $?' to get the resulting error. Also, CHECK YOUR FIREWALL!!!

View File

@@ -1,13 +1,15 @@
1. Finish README.md
2. Add command-line argument support:
1. Specify IP version in arg
2. Specify local hostname:port in arg (enclose in paranthesis if IPv6)
3. Specify remote hostname:port in arg (enclose in paranthesis if IPv6)
---SHOULD BE DONE--- 1. Specify IP version in arg
---NOT NEEDED--- 2. Specify local hostname:port in arg (enclose in paranthesis if IPv6)
---NOT NEEDED--- 3. Specify remote hostname:port in arg (enclose in paranthesis if IPv6)
4. Try making every aspect of the program configurable via args
3. Add support for configuration files, which can be specified via a command-line arg
3. Test UDP support
---SHOULD BE DONE---- 4. Fix Makefile - Doesn't recompile if source files have changed, only if .o files have.
4. Add support for configuration files, which can be specified via a command-line arg
5. Check IPv6 support for remote socket
---SHOULD BE DONE---- 5. Fix Makefile - Doesn't recompile if source files have changed, only if .o files have.
---SHOULD BE DONE--- 6. Check IPv6 support for remote socket

View File

@@ -1,5 +1,6 @@
#include "easysock.h"
int create_socket(int network, char transport) {
int domain;
int type;
@@ -25,7 +26,7 @@ int create_socket(int network, char transport) {
}
void create_addr(int network, char* address, int port,struct sockaddr* dest) {
int create_addr(int network, char* address, int port,struct sockaddr* dest) {
if (network == 4) {
struct sockaddr_in listen_address;
@@ -33,7 +34,7 @@ void create_addr(int network, char* address, int port,struct sockaddr* dest) {
listen_address.sin_port = htons(port);
inet_pton(AF_INET,address,&listen_address.sin_addr);
memcpy(dest,&listen_address,sizeof(listen_address));
return;
return 0;
} else if (network == 6) {
struct sockaddr_in6 listen_ipv6;
@@ -41,10 +42,10 @@ void create_addr(int network, char* address, int port,struct sockaddr* dest) {
listen_ipv6.sin6_port = htons(port);
inet_pton(AF_INET6,address,&listen_ipv6.sin6_addr);
memcpy(dest,&listen_ipv6,sizeof(listen_ipv6));
return;
return 0;
} else {
exit(-2);
return -202;
}
}
@@ -52,7 +53,7 @@ void create_addr(int network, char* address, int port,struct sockaddr* dest) {
int create_local (int network, char transport, char* address, int port,struct sockaddr* addr_struct) {
int socket = create_socket(network,transport);
if (socket < 0) {
printf("Something went wrong creating the socket: %s\n",strerror(errno));
return (-1 * errno);
}
create_addr(network,address,port,addr_struct);
int addrlen;
@@ -61,7 +62,7 @@ int create_local (int network, char transport, char* address, int port,struct so
} else if (network == 6) {
addrlen = sizeof(struct sockaddr_in6);
} else {
exit(-7);
return -207;
}
/* The value of addrlen should be the size of the 'sockaddr'.
@@ -70,38 +71,100 @@ int create_local (int network, char transport, char* address, int port,struct so
int i = bind (socket,addr_struct,(socklen_t)addrlen);
if (i < 0) {
printf("Something went wrong: %s\n",strerror(errno));
exit(-3);
return (-1 * errno);
}
return socket;
}
int create_remote (int network,char transport,char* address,int port) {
int create_remote (int network,char transport,char* address,int port,struct sockaddr* remote_addr_struct) {
struct addrinfo hints; /* Used to tell getaddrinfo what kind of address we want */
struct addrinfo* results; /* Used by getaddrinfo to store the addresses */
if (check_ip_ver(address) < 0) { /* If the address is a domain name */
int err_code;
char* port_str = malloc(10 * sizeof(char));
sprintf(port_str,"%d",port); /* getaddrinfo expects a string for its port */
memset(&hints,'\0',sizeof(hints));
hints.ai_socktype = char_to_socktype(transport);
err_code = getaddrinfo(address,port_str,&hints,&results);
if (err_code != 0) {
exit(err_code);
}
remote_addr_struct = results->ai_addr;
network = inet_to_int(results->ai_family);
} else {
create_addr(network,address,port,remote_addr_struct);
}
int socket = create_socket(network,transport);
if (socket == -1) {
exit(-1);
if (socket < 0) {
return (-1 * errno);
}
struct sockaddr remote_addr_struct;
create_addr(network,address,port,&remote_addr_struct);
int addrlen;
int addrlen;
if (network == 4) {
addrlen = sizeof(struct sockaddr_in);
} else if (network == 6) {
addrlen = sizeof(struct sockaddr_in6);
} else {
exit(-7);
return (-1 * errno);
}
/* The value of addrlen should be the size of the 'sockaddr'.
This should be set to the size of 'sockaddr_in' for IPv4, and 'sockaddr_in6' for IPv6.
See https://stackoverflow.com/questions/73707162/socket-bind-failed-with-invalid-argument-error-for-program-running-on-macos */
int i = connect(socket,&remote_addr_struct,(socklen_t)addrlen);
int i = connect(socket,remote_addr_struct,(socklen_t)addrlen);
if (i < 0) {
printf("Something went wrong: %s\n",strerror(errno));
exit(-3);
return (-1 * errno);
}
return socket;
}
int check_ip_ver(char* address) {
char buffer[16]; /* 16 chars - 128 bits - is enough to hold an ipv6 address */
if (inet_pton(AF_INET,address,buffer) == 1) {
return 4;
} else if (inet_pton(AF_INET6,address,buffer) == 1) {
return 6;
} else {
return -1;
}
}
int int_to_inet(int network) {
if (network == 4) {
return AF_INET;
} else if (network == 6) {
return AF_INET6;
} else {
return -207;
}
}
int inet_to_int(int af_type) {
if (af_type == AF_INET) {
return 4;
} else if (af_type == AF_INET6) {
return 6;
} else {
return -207;
}
}
int char_to_socktype(char transport) {
if (transport == 'T') {
return SOCK_STREAM;
} else if (transport == 'U') {
return SOCK_DGRAM;
} else {
return -250;
}
}

View File

@@ -2,7 +2,9 @@
#define EASYSOCK_H_
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
@@ -26,10 +28,10 @@ int create_socket(int network, char transport);
port is self-explanatory;
and dest is a pointer to the sockaddr struct that will be filled in.
The function exits with error code -2 if the network parameter contained neither '4'
The function returns with -202 if the network parameter contained neither '4'
nor '6'. */
void create_addr(int network, char* address, int port,struct sockaddr* dest);
int create_addr(int network, char* address, int port,struct sockaddr* dest);
@@ -37,18 +39,38 @@ void create_addr(int network, char* address, int port,struct sockaddr* dest);
_binds_ the addresses. It is used for local sockets (server sockets). Parameters are
same as above.
It prints the error returned by 'bind' if something went wrong, and exits with error code '-3'.*/
It prints the error returned by 'bind' if something went wrong, and returns ( -1 * errno ).*/
int create_local (int network, char transport, char* address, int port,struct sockaddr* addr_struct);
/* This function utilizes the same functions as 'create_local' but _connects_ to the
requested address. It is used for remoet sockets (client sockets). The paramters are same
as above.
requested address. It is used for remote sockets (client sockets). The paramters are same
as above. This function needs an empty 'sockaddr *' structure passed to it, which it will fill.
It prints the error returned by 'connect' if something went wrong, and exits with error code '-3'.*/
If something goes wrong, this function returns with ( -1 * errno ). */
int create_remote (int network,char transport,char* address,int port);
int create_remote (int network,char transport,char* address,int port,struct sockaddr* remote_addr_struct);
/* check_ip_ver - This function checks if the given string is an IPv4 address (returns 4),
IPv6 address (returns 6) or neither (returns -1). */
int check_ip_ver(char* address);
/* int_to_inet - Takes an int value (4 for IPv4, 6 for IPv6) and returns AF_INET or
AF_INET6 respectively. */
int int_to_inet(int network);
/* char_to_socktype - Takes a character that represents a transport-layer protocol
(currently only supports 'T' for TCP or 'U' for UDP - it returns -250 if
the given characters is neither of these) and return the appropriate SOCKTYPE value. */
int char_to_socktype(char transport);
/* inet_to_int - Takes an int value that corresponds to AF_INET or AF_INET6,
and returns the appropriate int value. */
int inet_to_int(int af_type);
#endif

107
main.c
View File

@@ -3,7 +3,8 @@
#include <unistd.h>
#include <stdlib.h>
#include "easysock.h"
#define PROG_NAME "basicproxy"
#define PROG_VER "0.01"
void forward_data(int from_fd, int to_fd) {
int n = 0;
char* buffer = malloc(3000*sizeof(char));
@@ -12,18 +13,24 @@ void forward_data(int from_fd, int to_fd) {
}
}
int check_ip_ver(char* address) {
char buffer[16]; /* 16 chars - 128 bits - is enough to hold an ipv6 address */
if (inet_pton(AF_INET,address,buffer) == 1) {
return 4;
} else if (inet_pton(AF_INET6,address,buffer) == 1) {
return 6;
} else {
return -1;
}
void print_prog_info() {
printf("%s [Local IP address] [local port] [remote IP address] [remote port]\n",PROG_NAME);
}
void print_version_info() {
printf("%s %s\n",PROG_NAME,PROG_VER);
}
void print_help_info() {
printf("\n%s - A simple TCP proxy written in C.\n\n",PROG_NAME);
printf("Syntax - ");
print_prog_info();
printf("[Local IP address] - The local address to bind to\n"
"[local port] - The local port to listen on\n"
"[remote IP address] - The remote IP to connect to\n"
"[remote port] - The remote port to connect to\n");
printf("\nExample: %s 127.0.0.1 3000 1.2.3.4 5000 - Listen on '127.0.0.1:3000', and forward all data from there to '1.2.3.4:5000'\n\n",PROG_NAME);
}
int main(int argc,char* argv[]) {
/* argv[1] = local address
@@ -31,6 +38,22 @@ int main(int argc,char* argv[]) {
argv[3] = remote address
argv[4] = remote port */
if (argc == 2) {
if (strcmp(argv[1],"-v") == 0 || strcmp(argv[1],"--version") == 0) {
print_version_info();
exit(0);
} else if (strcmp(argv[1],"-h") == 0 || strcmp(argv[1],"--help") == 0) {
print_help_info();
exit(0);
}
}
if (argc != 5) {
print_prog_info();
exit(230);
}
char* local_addr = argv[1];
int local_port = strtol(argv[2],NULL,10);
char* remote_addr = argv[3];
@@ -38,47 +61,57 @@ int main(int argc,char* argv[]) {
int preferred_local_network = check_ip_ver(local_addr);
int preferred_remote_network = check_ip_ver(remote_addr);
printf("Using %d for local\nUsing %d for remote\n",preferred_local_network,preferred_remote_network);
if ((preferred_local_network == -1) || (preferred_remote_network == -1)) {
exit(-7);
if (preferred_remote_network < 0) { /* This value will be less than 0 if the remote address is a domain name */
printf("Using %d for local\nUsing hostname for remote\n",preferred_local_network);
} else {
printf("Using %d for local\nUsing %d for remote\n",preferred_local_network,preferred_remote_network);
}
if (preferred_local_network == -1) {
exit(207); /* If the _local_ address isn't an IP address, then we've got problems. */
}
char preferred_transport = 'T';
struct sockaddr addr_struct;
int server_sock = create_local(preferred_local_network,preferred_transport,local_addr,local_port,&addr_struct);
int addrlen = sizeof(addr_struct);
if (server_sock < 0) {
exit(-1 * server_sock);
}
int addrlen;
if (check_ip_ver(local_addr) == 4) {
addrlen = sizeof(struct sockaddr_in);
} else if (check_ip_ver(local_addr) == 6) {
addrlen = sizeof(struct sockaddr_in6);
} else {
exit(207);
}
listen(server_sock,50); /* Arbitrary number, change later */
printf("Listening on %s:%d\n",local_addr,local_port);
struct sockaddr remote_addr_struct;
while (1) {
int from_client = accept(server_sock,&addr_struct,(socklen_t *)&addrlen);
int to_server = create_remote(preferred_remote_network,preferred_transport,remote_addr,remote_port);
int from_client = accept(server_sock,&addr_struct,(socklen_t *)&addrlen);
int to_server = create_remote(preferred_remote_network,preferred_transport,remote_addr,remote_port,&remote_addr_struct);
if (to_server < 0) {
exit(-1 * to_server);
}
printf("Connection established to %s:%d\n",remote_addr,remote_port);
if (fork() == 0) {
/* fork returns 0 for a child, so we're in the child's execution
right now */
close(server_sock);
printf("Connection established to %s:%d\n",remote_addr,remote_port);
if (fork() == 0) {
forward_data(from_client,to_server);
/* fork returns 0 for a child, so we're in the child's execution
right now */
close(server_sock);
if (fork() == 0) {
forward_data(from_client,to_server);
exit(0);
}
if (fork() == 0) {
forward_data(to_server,from_client);
exit(0);
}
exit(0);
}
if (fork() == 0) {
forward_data(to_server,from_client);
exit(0);
}
exit(0);
}
// recv(from_client,buffer,3000,0);
// printf("%s",buffer);
}