<commit_before>/**
 * @author: <NAME>
 * @file: ncd.c
 * Comp 429
 * Project 2 Phase III
 */

#include "ncd.h"

/*  Global Variables  */
int size, num_packets, num_tail, time_wait, done = 0;
u_int16_t port;
char entropy;
char* dst_ip;
u_int8_t ttl;

int icmp_fd, send_fd, recv_fd;
char packet_send[SIZE] = { 0 };
char icmp_send[128] = { 0 };
char packet_rcv[SIZE] = { 0 };
size_t send_len, icmp_ip_len, icmp_len, icmp_data_len, rcv_len;
struct addrinfo *res;
void *(*recv_data)(void*);

struct proto proto;

/*  Just returns current time as double, with most possible precision...  */
double get_time(void)
{
	struct timeval tv;
	double d;
	gettimeofday(&tv, NULL);
	d = ((double) tv.tv_usec) / 1000000. + (unsigned long) tv.tv_sec;
	return d;
}

int comp_det(char* address, u_int16_t port, char hl, size_t data_size,
		size_t num_packets, unsigned short ttl, size_t time_wait,
		int n_tail)
{
	/*size of udp data*/
	int udp_data_len = data_size;

	/* size of udp packet */
	int udp_len = udp_data_len + sizeof(struct udphdr);

	/* size of IP packet (IP header +  udp packet size*/
	send_len = udp_len + sizeof(struct ip);

	/* size of ICMP Echo message */
	icmp_data_len = 56;

	/*size of icmp packet*/
	icmp_len = sizeof(struct icmp) + icmp_data_len;

	/* size of ICMP reply + ip header */
	icmp_ip_len = sizeof(struct ip) + icmp_len;
	struct icmp *icmp; /* ICMP header */

	/*number of bytes sent*/
	int n;

	struct addrinfo hints = { 0 }; /* for get addrinfo */

	/* set up hints for getaddrinfo() */
	hints.ai_flags = AI_CANONNAME;
	hints.ai_protocol = IPPROTO_UDP;

	int err = getaddrinfo(address, NULL, &hints, &res);

	/*taken from http://stackoverflow.com/questions/17914550/getaddrinfo-error-success*/
	if(err != 0){
		if(err == EAI_SYSTEM)
			fprintf(stderr, "looking up %s: %s\n", address,
					strerror(errno));
		else
			fprintf(stderr, "looking up %s: %s\n", address,
					gai_strerror(err));
		exit(EXIT_FAILURE);
	}

	send_fd = socket(res->ai_family, SOCK_RAW, IPPROTO_UDP);
	if(send_fd == -1){
		perror("call to socket() failed");
		exit(EXIT_FAILURE);
	}

	/* set up our own ip header */
	int hdrincl = 1;

	int r = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
	if(setsockopt(send_fd, r, IP_HDRINCL, &hdrincl, sizeof(hdrincl)) == -1){
		perror("setsockopt() failed send");
		exit(EXIT_FAILURE);
	}/**/

	/* acquire socket for icmp messages*/

	int l = res->ai_family == AF_INET ? IPPROTO_ICMP : IPPROTO_ICMPV6;
	icmp_fd = socket(res->ai_family, SOCK_RAW, l);

	if(icmp_fd == -1){
		perror("call to socket() failed");
		exit(EXIT_FAILURE);    // consider doing something better here
	}

	/* set up our own IP header*/
	int icmp_hdrincl = 1;
	if(setsockopt(icmp_fd, r, IP_HDRINCL, &icmp_hdrincl,
			sizeof(icmp_hdrincl)) == -1){
		perror("setsockopt() failed icmp");
		exit(EXIT_FAILURE);
	}

	err = setuid(getuid());/*give up privileges */

	if(err < 0){
		perror("Elevated privliges not released");
		return EXIT_FAILURE;
	}

	struct udphdr *udp;
	if(res->ai_family == AF_INET){
		udp = (struct udphdr *) (packet_send + sizeof(struct ip));
		mkipv4(packet_send, send_len, res, IPPROTO_UDP);
		mkudphdr(udp, data_size, IPPROTO_UDP);
		mkipv4(icmp_send, send_len, res, IPPROTO_ICMP);
		mkicmpv4(icmp_send + (sizeof(struct ip)), icmp_len);

	}else if(res->ai_family == AF_INET6){
		udp = (struct udphdr *) (packet_send + sizeof(struct ip6_hdr));
		mkipv6(packet_send, send_len, res, IPPROTO_UDP);
		mkudphdr(udp, data_size, IPPROTO_UDP);
		mkipv6(icmp_send, send_len, res, IPPROTO_ICMPV6);
		mkicmpv6(icmp_send + (sizeof(struct ip6_hdr)), icmp_data_len);

	}else{
		errno = EPROTONOSUPPORT;
		perror("Protocol not supported");
		return EXIT_FAILURE;
	}

	recv_data = res->ai_family == AF_INET ? recv4 : recv6;
	double time;
	pthread_t threads[2];
	int rc;
	register int i;
	int ret = 0;
	void *status[2];
	if(entropy == 'b' || entropy == 'l'){

		done = 0;

		/* Acquire raw socket to listen for ICMP replies */
		recv_fd = socket(res->ai_family, SOCK_RAW, IPPROTO_ICMP);
		if(recv_fd == -1){
			perror("call to socket() failed");
			return EXIT_FAILURE;
		}

		/*increase size of receive buffer*/
		int size = 60 * 1024;
		setsockopt(recv_fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));

		rc = pthread_create(&threads[0], NULL, recv_data, &time);
		if(rc){
			printf(
					"ERROR; return code from pthread_create() is %d\n",
					rc);
			exit(-1);
		}

		int rc = pthread_create(&threads[1], NULL, send_train,
				status[1]);
		if(rc){
			printf(
					"ERROR; return code from pthread_create() is %d\n",
					rc);
			exit(-1);
		}

		for(i = 0; i < 2; ++i){
			rc = pthread_join(threads[i], &status[i]);
			if(rc){
				printf(
						"ERROR; return code from pthread_create() is %d\n",
						rc);
				exit(-1);
			}

			if( status[i] != NULL)
				ret = (int) status[i];

			if(ret){
				return EXIT_FAILURE;
			}
		}

		printf("%c %f sec\n", 'L', time);
		close(recv_fd);
	}

	sleep(3);    // sloppy replace with better metric

	if(entropy == 'b' || entropy == 'h'){

		done = 0;

		fill_data((udp + 1), data_size);
		mkudphdr(udp, data_size, IPPROTO_UDP);

		/* Acquire raw socket to listen for ICMP replies */
		recv_fd = socket(res->ai_family, SOCK_RAW, l);
		if(recv_fd == -1){
			perror("call to socket() failed");
			return EXIT_FAILURE;
		}

		/*increase size of receive buffer*/
		int size = 60 * 1024;
		setsockopt(recv_fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));

		rc = pthread_create(&threads[0], NULL, recv_data, &time);
		if(rc){
			printf(
					"ERROR; return code from pthread_create() is %d\n",
					rc);
			exit(-1);
		}

		int rc = pthread_create(&threads[1], NULL, send_train,
				(void *) &n_tail);
		if(rc){
			printf(
					"ERROR; return code from pthread_create() is %d\n",
					rc);
			exit(-1);
		}

		for(i = 0; i < 2; ++i){
			rc = pthread_join(threads[i], &status[i]);
			if(rc){
				printf(
						"ERROR; return code from pthread_create() is %d\n",
						rc);
				exit(-1);
			}
			if( status[i] != NULL)
				ret = (int) status[i];
		}
		printf("%c %f sec\n", 'H', time);
		close(recv_fd);
	}

	if(ret != 0)
		return EXIT_FAILURE;

	return EXIT_SUCCESS;
}

int mkipv4(void* buff, size_t size, struct addrinfo *res, u_int8_t proto)
{
	/* create IP header*/
	struct ip *ip = (struct ip *) buff;
	ip->ip_v = 4;
	ip->ip_hl = 5;
	ip->ip_len = htons(size);
	ip->ip_id = htons(1234);

	/* get a better way to assign my IP address!!!*/
	inet_pton(AF_INET, "192.168.1.101",  &ip->ip_src.s_addr);
	ip->ip_dst = ((struct sockaddr_in*) res->ai_addr)->sin_addr;
	ip->ip_off |= ntohs(IP_DF);
	ip->ip_ttl = ttl;
	ip->ip_p = proto;
	return 0;
}

int mkipv6(void* buff, size_t size, struct addrinfo *res, u_int8_t proto)
{
	struct ip6_hdr *ip = (struct ip6_hdr *) buff;
	ip->ip6_dst = ((struct sockaddr_in6*) res->ai_addr)->sin6_addr;
	inet_pton(AF_INET6, "192.168.1.101", &ip->ip6_src);
	ip->ip6_ctlun.ip6_un1.ip6_un1_flow = 0;
	ip->ip6_ctlun.ip6_un1.ip6_un1_hlim = ttl;
	ip->ip6_ctlun.ip6_un1.ip6_un1_nxt = htons(sizeof(struct ip6_hdr));
	ip->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(send_len);

	return 0;
}

int mkudphdr(void* buff, size_t udp_data_len, u_int8_t proto)
{
	struct ip* ip = buff;
	ip--;
	int udp_len = udp_data_len + sizeof(struct udphdr);
	char pseudo[SIZE] = { 0 }; /* buffer for pseudo header */
	struct udphdr *udp = (struct udphdr *) buff;
	udp->uh_sport = htons(port); /* set source port*/
	udp->uh_dport = htons(port); /* set destination port */
	udp->uh_ulen = htons(udp_len); /* set udp length */
	udp->check = 0;/* zero out the udp checksum */

	/*printf("ip: %d\n", ip);
	 printf("udp, %d, udp+1: %d\n", udp, udp + 1);
	 fill_data(udp + 1, udp_data_len);/**/

	/* pseudo header for udp checksum */
	struct pseudo_header *ps = (struct pseudo_header *) pseudo;
	ps->source = ip->ip_src.s_addr;
	ps->dest = ip->ip_dst.s_addr;
	ps->zero = 0;
	ps->proto = proto;
	ps->len = htons(udp_len);

	/*printf("udp_data: %d, udp_len: %d, ps: %d, ps_len %d\n", udp_data_len,
	 udp_len, sizeof(struct pseudo_header),
	 udp_len + sizeof(struct pseudo_header));
	 printf("ps: %d, ps+1: %d\n", ps, ps+1);/**/

	/*copy udp packet into pseudo header buffer to calculate checksum*/
	memcpy(ps + 1, udp, udp_len);

	/* set udp checksum */

	udp->check = ip_checksum(ps, udp_len + sizeof(struct pseudo_header));

	return 0;
}

int mkicmpv4(void *buff, size_t datalen)<commit_msg> updated checksum access to BSD only<commit_after>/**
 * @author: <NAME>
 * @file: ncd.c
 * Comp 429
 * Project 2 Phase III
 */

#include "ncd.h"

/*  Global Variables  */
int size, num_packets, num_tail, time_wait, done = 0;
u_int16_t port;
char entropy;
char* dst_ip;
u_int8_t ttl;

int icmp_fd, send_fd, recv_fd;
char packet_send[SIZE] = { 0 };
char icmp_send[128] = { 0 };
char packet_rcv[SIZE] = { 0 };
size_t send_len, icmp_ip_len, icmp_len, icmp_data_len, rcv_len;
struct addrinfo *res;
void *(*recv_data)(void*);

struct proto proto;

/*  Just returns current time as double, with most possible precision...  */
double get_time(void)
{
	struct timeval tv;
	double d;
	gettimeofday(&tv, NULL);
	d = ((double) tv.tv_usec) / 1000000. + (unsigned long) tv.tv_sec;
	return d;
}

int comp_det(char* address, u_int16_t port, char hl, size_t data_size,
		size_t num_packets, unsigned short ttl, size_t time_wait,
		int n_tail)
{
	/*size of udp data*/
	int udp_data_len = data_size;

	/* size of udp packet */
	int udp_len = udp_data_len + sizeof(struct udphdr);

	/* size of IP packet (IP header +  udp packet size*/
	send_len = udp_len + sizeof(struct ip);

	/* size of ICMP Echo message */
	icmp_data_len = 56;

	/*size of icmp packet*/
	icmp_len = sizeof(struct icmp) + icmp_data_len;

	/* size of ICMP reply + ip header */
	icmp_ip_len = sizeof(struct ip) + icmp_len;
	struct icmp *icmp; /* ICMP header */

	/*number of bytes sent*/
	int n;

	struct addrinfo hints = { 0 }; /* for get addrinfo */

	/* set up hints for getaddrinfo() */
	hints.ai_flags = AI_CANONNAME;
	hints.ai_protocol = IPPROTO_UDP;

	int err = getaddrinfo(address, NULL, &hints, &res);

	/*taken from http://stackoverflow.com/questions/17914550/getaddrinfo-error-success*/
	if(err != 0){
		if(err == EAI_SYSTEM)
			fprintf(stderr, "looking up %s: %s\n", address,
					strerror(errno));
		else
			fprintf(stderr, "looking up %s: %s\n", address,
					gai_strerror(err));
		exit(EXIT_FAILURE);
	}

	send_fd = socket(res->ai_family, SOCK_RAW, IPPROTO_UDP);
	if(send_fd == -1){
		perror("call to socket() failed");
		exit(EXIT_FAILURE);
	}

	/* set up our own ip header */
	int hdrincl = 1;

	int r = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
	if(setsockopt(send_fd, r, IP_HDRINCL, &hdrincl, sizeof(hdrincl)) == -1){
		perror("setsockopt() failed send");
		exit(EXIT_FAILURE);
	}/**/

	/* acquire socket for icmp messages*/

	int l = res->ai_family == AF_INET ? IPPROTO_ICMP : IPPROTO_ICMPV6;
	icmp_fd = socket(res->ai_family, SOCK_RAW, l);

	if(icmp_fd == -1){
		perror("call to socket() failed");
		exit(EXIT_FAILURE);    // consider doing something better here
	}

	/* set up our own IP header*/
	int icmp_hdrincl = 1;
	if(setsockopt(icmp_fd, r, IP_HDRINCL, &icmp_hdrincl,
			sizeof(icmp_hdrincl)) == -1){
		perror("setsockopt() failed icmp");
		exit(EXIT_FAILURE);
	}

	err = setuid(getuid());/*give up privileges */

	if(err < 0){
		perror("Elevated privliges not released");
		return EXIT_FAILURE;
	}

	struct udphdr *udp;
	if(res->ai_family == AF_INET){
		udp = (struct udphdr *) (packet_send + sizeof(struct ip));
		mkipv4(packet_send, send_len, res, IPPROTO_UDP);
		mkudphdr(udp, data_size, IPPROTO_UDP);
		mkipv4(icmp_send, send_len, res, IPPROTO_ICMP);
		mkicmpv4(icmp_send + (sizeof(struct ip)), icmp_len);

	}else if(res->ai_family == AF_INET6){
		udp = (struct udphdr *) (packet_send + sizeof(struct ip6_hdr));
		mkipv6(packet_send, send_len, res, IPPROTO_UDP);
		mkudphdr(udp, data_size, IPPROTO_UDP);
		mkipv6(icmp_send, send_len, res, IPPROTO_ICMPV6);
		mkicmpv6(icmp_send + (sizeof(struct ip6_hdr)), icmp_data_len);

	}else{
		errno = EPROTONOSUPPORT;
		perror("Protocol not supported");
		return EXIT_FAILURE;
	}

	recv_data = res->ai_family == AF_INET ? recv4 : recv6;
	double time;
	pthread_t threads[2];
	int rc;
	register int i;
	int ret = 0;
	void *status[2];
	if(entropy == 'b' || entropy == 'l'){

		done = 0;

		/* Acquire raw socket to listen for ICMP replies */
		recv_fd = socket(res->ai_family, SOCK_RAW, IPPROTO_ICMP);
		if(recv_fd == -1){
			perror("call to socket() failed");
			return EXIT_FAILURE;
		}

		/*increase size of receive buffer*/
		int size = 60 * 1024;
		setsockopt(recv_fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));

		rc = pthread_create(&threads[0], NULL, recv_data, &time);
		if(rc){
			printf(
					"ERROR; return code from pthread_create() is %d\n",
					rc);
			exit(-1);
		}

		int rc = pthread_create(&threads[1], NULL, send_train,
				status[1]);
		if(rc){
			printf(
					"ERROR; return code from pthread_create() is %d\n",
					rc);
			exit(-1);
		}

		for(i = 0; i < 2; ++i){
			rc = pthread_join(threads[i], &status[i]);
			if(rc){
				printf(
						"ERROR; return code from pthread_create() is %d\n",
						rc);
				exit(-1);
			}

			if( status[i] != NULL)
				ret = (int) status[i];

			if(ret){
				return EXIT_FAILURE;
			}
		}

		printf("%c %f sec\n", 'L', time);
		close(recv_fd);
	}

	sleep(3);    // sloppy replace with better metric

	if(entropy == 'b' || entropy == 'h'){

		done = 0;

		fill_data((udp + 1), data_size);
		mkudphdr(udp, data_size, IPPROTO_UDP);

		/* Acquire raw socket to listen for ICMP replies */
		recv_fd = socket(res->ai_family, SOCK_RAW, l);
		if(recv_fd == -1){
			perror("call to socket() failed");
			return EXIT_FAILURE;
		}

		/*increase size of receive buffer*/
		int size = 60 * 1024;
		setsockopt(recv_fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));

		rc = pthread_create(&threads[0], NULL, recv_data, &time);
		if(rc){
			printf(
					"ERROR; return code from pthread_create() is %d\n",
					rc);
			exit(-1);
		}

		int rc = pthread_create(&threads[1], NULL, send_train,
				(void *) &n_tail);
		if(rc){
			printf(
					"ERROR; return code from pthread_create() is %d\n",
					rc);
			exit(-1);
		}

		for(i = 0; i < 2; ++i){
			rc = pthread_join(threads[i], &status[i]);
			if(rc){
				printf(
						"ERROR; return code from pthread_create() is %d\n",
						rc);
				exit(-1);
			}
			if( status[i] != NULL)
				ret = (int) status[i];
		}
		printf("%c %f sec\n", 'H', time);
		close(recv_fd);
	}

	if(ret != 0)
		return EXIT_FAILURE;

	return EXIT_SUCCESS;
}

int mkipv4(void* buff, size_t size, struct addrinfo *res, u_int8_t proto)
{
	/* create IP header*/
	struct ip *ip = (struct ip *) buff;
	ip->ip_v = 4;
	ip->ip_hl = 5;
	ip->ip_len = htons(size);
	ip->ip_id = htons(1234);

	/* get a better way to assign my IP address!!!*/
	inet_pton(AF_INET, "192.168.1.101",  &ip->ip_src.s_addr);
	ip->ip_dst = ((struct sockaddr_in*) res->ai_addr)->sin_addr;
	ip->ip_off |= ntohs(IP_DF);
	ip->ip_ttl = ttl;
	ip->ip_p = proto;
	return 0;
}

int mkipv6(void* buff, size_t size, struct addrinfo *res, u_int8_t proto)
{
	struct ip6_hdr *ip = (struct ip6_hdr *) buff;
	ip->ip6_dst = ((struct sockaddr_in6*) res->ai_addr)->sin6_addr;
	inet_pton(AF_INET6, "192.168.1.101", &ip->ip6_src);
	ip->ip6_ctlun.ip6_un1.ip6_un1_flow = 0;
	ip->ip6_ctlun.ip6_un1.ip6_un1_hlim = ttl;
	ip->ip6_ctlun.ip6_un1.ip6_un1_nxt = htons(sizeof(struct ip6_hdr));
	ip->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(send_len);

	return 0;
}

int mkudphdr(void* buff, size_t udp_data_len, u_int8_t proto)
{
	struct ip* ip = buff;
	ip--;
	int udp_len = udp_data_len + sizeof(struct udphdr);
	char pseudo[SIZE] = { 0 }; /* buffer for pseudo header */
	struct udphdr *udp = (struct udphdr *) buff;
	udp->uh_sport = htons(port); /* set source port*/
	udp->uh_dport = htons(port); /* set destination port */
	udp->uh_ulen = htons(udp_len); /* set udp length */
	udp->uh_sum = 0;/* zero out the udp checksum */

	/*printf("ip: %d\n", ip);
	 printf("udp, %d, udp+1: %d\n", udp, udp + 1);
	 fill_data(udp + 1, udp_data_len);/**/

	/* pseudo header for udp checksum */
	struct pseudo_header *ps = (struct pseudo_header *) pseudo;
	ps->source = ip->ip_src.s_addr;
	ps->dest = ip->ip_dst.s_addr;
	ps->zero = 0;
	ps->proto = proto;
	ps->len = htons(udp_len);

	/*printf("udp_data: %d, udp_len: %d, ps: %d, ps_len %d\n", udp_data_len,
	 udp_len, sizeof(struct pseudo_header),
	 udp_len + sizeof(struct pseudo_header));
	 printf("ps: %d, ps+1: %d\n", ps, ps+1);/**/

	/*copy udp packet into pseudo header buffer to calculate checksum*/
	memcpy(ps + 1, udp, udp_len);

	/* set udp checksum */

	udp->uh_sum = ip_checksum(ps, udp_len + sizeof(struct pseudo_header));

	return 0;
}

int mkicmpv4(void *buff, size_t datalen)
{'fraction_non_alphanumeric': 0.159563627644908, 'fraction_numerical': 0.01990049751243781, 'mean_word_length': 3.751922529193962, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 85, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '383508', 'n_tokens_mistral': 7525, 'n_tokens_neox': 6863, 'n_words': 1675}