Last active
February 10, 2017 11:12
-
-
Save sharmaeklavya2/85486d5280b960e775ffad8e042beb44 to your computer and use it in GitHub Desktop.
My netcat clone
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _POSIX_SOURCE | |
#include<stdio.h> | |
#include<stdlib.h> | |
#include<string.h> | |
#include<sys/types.h> | |
#include<sys/socket.h> | |
#include<netinet/in.h> | |
#include<arpa/inet.h> | |
#include<unistd.h> | |
#include<signal.h> | |
#include<sys/wait.h> | |
#ifndef __cplusplus | |
#define true 1 | |
#define false 0 | |
typedef int bool; | |
#endif | |
#define BUFSIZE 16 | |
#define MAX_CONNS 2 | |
char buffer[BUFSIZE]; | |
char app_name[] = "ekunc"; | |
#define DEBUG | |
void set_sockaddr_in(struct sockaddr_in* p_saddr, const char* ipaddr, int port) | |
{ | |
p_saddr->sin_family = AF_INET; | |
p_saddr->sin_port = htons(port); | |
p_saddr->sin_addr.s_addr = inet_addr(ipaddr); | |
memset(p_saddr->sin_zero, '\0', sizeof (p_saddr->sin_zero)); | |
} | |
void parse_sockaddr_in(struct sockaddr_in* p_saddr, char* ipaddr, int* p_port) | |
{ | |
*p_port = ntohs(p_saddr->sin_port); | |
strcpy(ipaddr, inet_ntoa(p_saddr->sin_addr)); | |
} | |
int make_socket_reusable(int sockfd) | |
{ | |
int on=1, err; | |
err = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on); | |
if(err == -1) | |
{perror(app_name); return 11;} | |
return 0; | |
} | |
void get_sock_info(int sockfd, char* my_ipaddr, int* p_my_port, char* peer_ipaddr, int* p_peer_port) | |
{ | |
int err; | |
socklen_t addr_len; | |
struct sockaddr_in my_addr, peer_addr; | |
memset(&my_addr, 0, sizeof my_addr); | |
memset(&peer_addr, 0, sizeof peer_addr); | |
addr_len = sizeof my_addr; | |
err = getsockname(sockfd, (struct sockaddr*)&my_addr, &addr_len); | |
if(err == -1) | |
perror(app_name); | |
parse_sockaddr_in(&my_addr, my_ipaddr, p_my_port); | |
addr_len = sizeof peer_addr; | |
err = getpeername(sockfd, (struct sockaddr*)&peer_addr, &addr_len); | |
if(err == -1) | |
perror(app_name); | |
parse_sockaddr_in(&peer_addr, peer_ipaddr, p_peer_port); | |
} | |
void print_sock_info(int sockfd, FILE* stream) | |
{ | |
char my_ipaddr[20], peer_ipaddr[20]; | |
int my_port, peer_port; | |
get_sock_info(sockfd, my_ipaddr, &my_port, peer_ipaddr, &peer_port); | |
fprintf(stream, "Connected to %s:%d via %s:%d\n", peer_ipaddr, peer_port, my_ipaddr, my_port); | |
} | |
int read_loop(int sockfd) | |
{ | |
/* | |
pid_t pid = getpid(); | |
fprintf(stderr, "process %d: started read_loop\n", pid); | |
*/ | |
while(true) | |
{ | |
int err = recv(sockfd, buffer, BUFSIZE, 0); | |
if(err == -1) | |
{ | |
perror(app_name); | |
return 31; | |
} | |
else if(err == 0) | |
return 0; | |
else | |
printf("%s", buffer); | |
} | |
} | |
int write_loop(int sockfd) | |
{ | |
/* | |
pid_t pid = getpid(); | |
fprintf(stderr, "process %d: started write_loop\n", pid); | |
*/ | |
while(fgets(buffer, BUFSIZE, stdin) != NULL) | |
{ | |
int err = send(sockfd, buffer, BUFSIZE, 0); | |
if(err == -1) | |
{ | |
perror(app_name); | |
close(sockfd); | |
return 41; | |
} | |
} | |
close(sockfd); | |
return 0; | |
} | |
int interact(int sockfd) | |
{ | |
pid_t rchild_pid, wchild_pid; | |
char role = 'm'; | |
// 'r': reader, 'w': writer, 'm': moderator | |
rchild_pid = fork(); | |
if(rchild_pid == -1) | |
{perror(app_name); return 51;} | |
else if(rchild_pid == 0) | |
role = 'r'; | |
if(role == 'm') | |
{ | |
wchild_pid = fork(); | |
if(wchild_pid == -1) | |
{perror(app_name); return 52;} | |
else if(wchild_pid == 0) | |
role = 'w'; | |
} | |
if(role == 'w') | |
return write_loop(sockfd); | |
else if(role == 'r') | |
return read_loop(sockfd); | |
else | |
{ | |
int status; | |
wait(&status); | |
int exit_status = WEXITSTATUS(status); | |
kill(rchild_pid, SIGTERM); | |
kill(wchild_pid, SIGTERM); | |
return exit_status; | |
} | |
} | |
int tcp_client(const char* ipaddr, int port) | |
{ | |
int sockfd, err; | |
struct sockaddr_in server_addr; | |
sockfd = socket(PF_INET, SOCK_STREAM, 0); | |
if(sockfd == -1) | |
{perror(app_name); return 61;} | |
#ifdef DEBUG | |
make_socket_reusable(sockfd); | |
#endif | |
set_sockaddr_in(&server_addr, ipaddr, port); | |
err = connect(sockfd, (struct sockaddr*)&server_addr, sizeof server_addr); | |
if(err == -1) | |
{perror(app_name); return 62;} | |
print_sock_info(sockfd, stderr); | |
return interact(sockfd); | |
} | |
int tcp_server(int port) | |
{ | |
int sockfd, sockfd2, err; | |
struct sockaddr_in addr; | |
struct sockaddr_in addr2; | |
sockfd = socket(PF_INET, SOCK_STREAM, 0); | |
if(sockfd == -1) | |
{perror(app_name); return 71;} | |
#ifdef DEBUG | |
make_socket_reusable(sockfd); | |
#endif | |
set_sockaddr_in(&addr, "0.0.0.0", port); | |
memset(buffer, '0', BUFSIZE); | |
err = bind(sockfd, (struct sockaddr*)&addr, sizeof addr); | |
if(err == -1) | |
{perror(app_name); return 72;} | |
fprintf(stderr, "Listening on port %d\n", port); | |
err = listen(sockfd, MAX_CONNS); | |
if(err == -1) | |
{perror(app_name); return 73;} | |
socklen_t addr_size = sizeof addr2; | |
sockfd2 = accept(sockfd, (struct sockaddr*)&addr2, &addr_size); | |
if(sockfd2 == -1) | |
{perror(app_name); return 74;} | |
#ifdef DEBUG | |
make_socket_reusable(sockfd2); | |
#endif | |
print_sock_info(sockfd2, stderr); | |
return interact(sockfd2); | |
} | |
// Command-line processing | |
int main(int argc, char** argv) | |
{ | |
const char usage[] = "usage: %s (-l | host) port\n"; | |
bool err = false; | |
bool is_server; | |
int port; | |
char* host; | |
if(argc != 3) | |
{ | |
fprintf(stderr, usage, argv[0]); | |
return 1; | |
} | |
if(argv[1][0] == '-') | |
{ | |
if(argv[1][1] == 'l') | |
is_server = true; | |
else | |
err = true; | |
} | |
else | |
{ | |
is_server = false; | |
host = argv[1]; | |
} | |
port = atoi(argv[2]); | |
if(port == 0) | |
err = true; | |
if(err) | |
{ | |
fprintf(stderr, usage, argv[0]); | |
return 1; | |
} | |
else if(is_server) | |
return tcp_server(port); | |
else | |
return tcp_client(host, port); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment