Skip to content

Instantly share code, notes, and snippets.

@sharmaeklavya2
Last active February 10, 2017 11:12
Show Gist options
  • Save sharmaeklavya2/85486d5280b960e775ffad8e042beb44 to your computer and use it in GitHub Desktop.
Save sharmaeklavya2/85486d5280b960e775ffad8e042beb44 to your computer and use it in GitHub Desktop.
My netcat clone
#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