diff --git a/traceroute/.gitignore b/traceroute/.gitignore new file mode 100644 index 00000000..66b75ec7 --- /dev/null +++ b/traceroute/.gitignore @@ -0,0 +1,2 @@ +traceroute +ft_traceroute diff --git a/traceroute/Makefile b/traceroute/Makefile new file mode 100644 index 00000000..c1b7779a --- /dev/null +++ b/traceroute/Makefile @@ -0,0 +1,68 @@ +# **************************************************************************** # +# # +# ::: :::::::: # +# Makefile :+: :+: :+: # +# +:+ +:+ +:+ # +# By: wescande +#+ +:+ +#+ # +# +#+#+#+#+#+ +#+ # +# Created: 2016/08/29 21:32:58 by wescande #+# #+# # +# Updated: 2017/10/08 14:36:33 by jhalford ### ########.fr # +# # +# **************************************************************************** # + +SHELL := bash + +NAME = ft_traceroute + +CC = gcc +RM = rm -rf 2>&- +W_FLAGS = -Wall -Wextra -Werror +D_FLAGS = -D _GNU_SOURCE +FLAGS = $(W_FLAGS) $(D_FLAGS) + +LEN_NAME = `printf "%s" $(NAME) |wc -c` +DELTA = $$(echo "$$(tput cols)-31-$(LEN_NAME)"|bc) + +SRC_DIR = ./ +INC_DIR = ./ +OBJ_DIR = objs/ + +SRC_BASE = \ +main.c\ +traceroute.c\ +cksum.c\ +rs.c\ +epoch.c\ +net.c\ +cliopts.c\ +error.c\ + +SRCS = $(addprefix $(SRC_DIR), $(SRC_BASE)) +OBJS = $(addprefix $(OBJ_DIR), $(SRC_BASE:.c=.o)) +NB = $(words $(SRC_BASE)) +INDEX = 0 + +all : + @make -j $(NAME) + +$(NAME): $(OBJ_DIR) $(OBJS) $(CLIENT_OBJ) + $(CC) $(OBJS) -o $@ -I $(INC_DIR) $(CLIENT_OBJ) $(FLAGS) -lm + # sudo setcap cap_net_raw+ep $@ 2>&- + +$(OBJ_DIR) : + @mkdir -p $(OBJ_DIR) + +$(OBJ_DIR)%.o : $(SRC_DIR)%.c | $(OBJ_DIR) + $(CC) $(FLAGS) $(OBJ_FLAG) -MMD -c $< -o $@ -I $(INC_DIR) + +clean: + $(RM) $(OBJ_DIR) + +re: fclean all + +fclean: clean + $(RM) $(NAME) + +.PHONY : fclean clean re + +-include $(OBJS:.o=.d) diff --git a/traceroute/cksum.c b/traceroute/cksum.c new file mode 100644 index 00000000..62c94bdf --- /dev/null +++ b/traceroute/cksum.c @@ -0,0 +1,29 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* cksum.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/10/08 12:45:43 by jhalford #+# #+# */ +/* Updated: 2017/10/08 12:48:41 by jhalford ### ########.fr */ +/* */ +/* ************************************************************************** */ + +unsigned short cksum(void *b, int len) +{ + unsigned short *buf; + unsigned int sum; + + buf = b; + sum = 0; + while (len > 1) + { + sum += *((unsigned short*)buf++); + len -= 2; + } + if (len == 1) + sum += *(unsigned char*)buf; + sum = (sum >> 16) + (sum & 0xFFFF); + return (~(sum + (sum >> 16))); +} diff --git a/traceroute/cliopts.c b/traceroute/cliopts.c new file mode 100644 index 00000000..5a7bd001 --- /dev/null +++ b/traceroute/cliopts.c @@ -0,0 +1,132 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* cliopts_get.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/03/14 20:04:04 by jhalford #+# #+# */ +/* Updated: 2017/04/02 20:45:11 by jhalford ### ########.fr */ +/* */ +/* ************************************************************************** */ + +/* +** void *data must be a structure starting with `int flag` +** to do polymorphism with t_data_template ! +*/ + +#include "cliopts.h" + +t_cliopts *cliopts_getmap_long(t_cliopts opt_map[], char *arg) +{ + int i; + + i = -1; + while (opt_map[++i].c) + if (!strcmp(opt_map[i].str, arg)) + return (&opt_map[i]); + return (NULL); +} + +t_cliopts *cliopts_getmap_short(t_cliopts opt_map[], char arg) +{ + int i; + + i = -1; + while (opt_map[++i].c) + if (opt_map[i].c == arg) + return (&opt_map[i]); + return (NULL); +} + +static char *check_required(char ***av, char *arg) +{ + char *ret; + + if (!av || !*av) + return (NULL); + if (!arg || !*arg || !*(arg + 1)) + return (*++(*av)); + ret = arg + 1; + return (ret); +} + +static int cliopts_parse_short( + char ***av, t_cliopts opt_map[], void *data) +{ + t_cliopts *map; + char *arg; + int i; + char *tmp; + + arg = **av + 1; + i = -1; + while (arg[++i] && !(tmp = NULL)) + { + if (!(map = cliopts_getmap_short(opt_map, arg[i]))) + return (ERR_SET(E_CO_INV, arg[i])); + ((t_data_template*)data)->flag |= map->flag_on; + ((t_data_template*)data)->flag &= ~map->flag_off; + if (map->get) + { + if (map->arg_required && !(tmp = check_required(av, arg + i))) + return (ERR_SET(E_CO_MISS, *arg)); + tmp = tmp ? tmp : **av; + if ((map->get)(tmp, data)) + return (ERR_SET(E_CO_MISS, *arg)); + if (map->arg_required) + break ; + } + } + return (++(*av) ? 0 : 0); +} + +static int cliopts_parse_long( + char ***av, t_cliopts opt_map[], void *data) +{ + t_cliopts *map; + char *arg; + char *tmp; + + arg = **av + 2; + tmp = NULL; + if (!(map = cliopts_getmap_long(opt_map, arg))) + return (ERR_SET(E_CO_INVL, arg)); + ((t_data_template*)data)->flag |= map->flag_on; + ((t_data_template*)data)->flag &= ~map->flag_off; + if (map->get) + { + if (map->arg_required && !(tmp = check_required(av, NULL))) + return (ERR_SET(E_CO_MISS, *arg)); + if ((map->get)(tmp, data)) + return (ERR_SET(E_CO_MISSL, arg)); + } + ++(*av); + return (0); +} + +int cliopts_get(char **av, t_cliopts opt_map[], void *data) +{ + if (!av) + return (1); + av++; + while (av && *av) + { + if (strcmp(*av, "-") == 0 || (strcmp(*av, "--") == 0 && av++)) + break ; + else if ((*av)[0] == '-' && (*av)[1] == '-') + { + if (cliopts_parse_long(&av, opt_map, data)) + return (1); + } + else if ((*av)[0] == '-') + { + if (cliopts_parse_short(&av, opt_map, data)) + return (1); + } + else + break ; + } + ((t_data_template*)data)->av_data = av; + return (0); +} diff --git a/traceroute/cliopts.h b/traceroute/cliopts.h new file mode 100644 index 00000000..cb12f929 --- /dev/null +++ b/traceroute/cliopts.h @@ -0,0 +1,40 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* cliopts.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/03/14 20:22:56 by jhalford #+# #+# */ +/* Updated: 2017/10/07 18:04:53 by jhalford ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#pragma once + +# include "error.h" +# include + +typedef struct s_cliopts t_cliopts; +typedef struct s_data_template t_data_template; +typedef long long t_flag; + +struct s_cliopts +{ + char c; + char *str; + t_flag flag_on; + t_flag flag_off; + int (*get)(); // (char *arg, void *data) + int arg_required:1; +}; + +struct s_data_template +{ + t_flag flag; + char **av_data; +}; + +int cliopts_get(char **av, t_cliopts opt_map[], void *data); +t_cliopts *cliopts_getmap_long(t_cliopts opt_map[], char *arg); +t_cliopts *cliopts_getmap_short(t_cliopts opt_map[], char arg); diff --git a/traceroute/epoch.c b/traceroute/epoch.c new file mode 100644 index 00000000..e567150d --- /dev/null +++ b/traceroute/epoch.c @@ -0,0 +1,31 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* epoch.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/10/07 17:58:42 by jhalford #+# #+# */ +/* Updated: 2017/10/08 13:15:50 by jhalford ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "traceroute.h" + +uint64_t epoch_micro(void) +{ + struct timeval tv; + + if (gettimeofday(&tv, NULL)) + return (0); + return (tv.tv_sec * 1000000 + tv.tv_usec); +} + +double time_milli(void) +{ + struct timeval tv; + + if (gettimeofday(&tv, NULL)) + return (0); + return ((double)(tv.tv_sec * 1000. + (double)tv.tv_usec / 1000.)); +} diff --git a/traceroute/error.c b/traceroute/error.c new file mode 100644 index 00000000..cbc459dc --- /dev/null +++ b/traceroute/error.c @@ -0,0 +1,68 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* error.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/03/14 16:47:00 by jhalford #+# #+# */ +/* Updated: 2017/03/25 01:53:25 by jhalford ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "error.h" + +char g_error_msglist[E_MAX][ERRMSG_MAX_SIZE] = +{ + "unknown error 0", + "invalid option -%c", + "invalid option --%s", + "option '%c' awaits argument(s): please don't combine", + "option '%c': missing argument", + "option '%s': missing argument", + "%s: no such file or directory", + "%s: Is a directory", + "%s: Permission denied", +}; + +int g_errnum = 0; +char *g_errmsg = NULL; +char **g_argv; + +int error_set(int n, ...) +{ + va_list ap; + + g_errnum = n; + va_start(ap, n); + if (g_errmsg) + { + free(g_errmsg); + g_errmsg = NULL; + } + vasprintf(&g_errmsg, g_error_msglist[n], ap); + return (g_errnum); +} + +int ft_perror(char *utility) +{ + utility = utility ? utility : g_argv[0]; + ERR_MSG(utility, g_errmsg); + return (g_errnum); +} + +void ft_usage(char *format, ...) +{ + va_list ap; + char *usage; + + va_start(ap, format); + usage = NULL; + vasprintf(&usage, format, ap); + dprintf(2, "usage: %s\n", usage); + if (usage) + { + free(usage); + usage = NULL; + } +} diff --git a/traceroute/error.h b/traceroute/error.h new file mode 100644 index 00000000..4ff21d9c --- /dev/null +++ b/traceroute/error.h @@ -0,0 +1,64 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* error.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/03/14 15:34:21 by jhalford #+# #+# */ +/* Updated: 2017/05/15 17:37:29 by ariard ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef ERROR_H +# define ERROR_H + +# include +# include +# include + +/* +** DEBUG with malloc +*/ +# define DG_MSG "{inv}{ran}%5i{yel}%21s {bol}{blu}%-3d{eoc}" +# define DG_ARGS getpid(), getpid(), ft_path_notdir(__FILE__), __LINE__ +# define DG(s, ...) dprintf(STDBUG,DG_MSG s "{eoc}\n",DG_ARGS,##__VA_ARGS__) + +/* +** DEBUG with no malloc +*/ +# define DG2 ft_putstr(__FILE__"\t");ft_putnbr(__LINE__) +# define DGW(d) DG2;d;ft_putchar('\n') +# define DGS(s) DGW(ft_putstr(": "s"=")) +# define DGSN(s, n) DGW(ft_putstr(": "s"=");ft_putnbr(n)) +# define DGSH(s, n) DGW(ft_putstr(": "s"=");ft_putnbr_hex(n)) + +# define ERR_PROTO(u, m) "%s: %s\n", u, m +# define ERR_MSG(u, m) dprintf(2, ERR_PROTO(u, m)) +# define ERR_SET(n, ...) error_set(n, ##__VA_ARGS__) +# define ERRMSG_MAX_SIZE 150 + +enum e_errors +{ + E_NOERR, + E_CO_INV, + E_CO_INVL, + E_CO_MULT, + E_CO_MISS, + E_CO_MISSL, + E_SYS_NOFILE, + E_SYS_ISDIR, + E_SYS_NOPERM, + E_MAX, +}; + +extern char g_error_msg[E_MAX][ERRMSG_MAX_SIZE]; +extern char *g_errmsg; +extern int g_errnum; +extern char **g_argv; + +int error_set(int n, ...); +int ft_perror(char *utility); +void ft_usage(char *format, ...); + +#endif diff --git a/traceroute/main.c b/traceroute/main.c new file mode 100644 index 00000000..63f55964 --- /dev/null +++ b/traceroute/main.c @@ -0,0 +1,56 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* main.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/10/08 17:18:05 by jhalford #+# #+# */ +/* Updated: 2017/10/08 17:55:15 by jhalford ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "traceroute.h" + +int g_pid = -1; + +struct addrinfo *resolve_host(char *hostname, char ip[]) +{ + struct addrinfo *result; + struct addrinfo hints; + struct sockaddr_in *addr; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags |= AI_CANONNAME; + if (getaddrinfo(hostname, NULL, &hints, &result) != 0) + { + perror("getaddrinfo"); + exit(1); + } + addr = (struct sockaddr_in*)result->ai_addr; + inet_ntop(AF_INET, &(addr->sin_addr), ip, INET_ADDRSTRLEN); + return (result); +} + +int main(int ac, char **av) +{ + struct addrinfo *result; + char ip[INET_ADDRSTRLEN]; + + if (ac != 2) + { + ft_usage("%s \n", av[0]); + return (1); + } + result = resolve_host(av[1], ip); + if (result->ai_next) + printf("traceroute: Warning: %s has multiple addresses; using %s\n", + result->ai_canonname, ip); + printf("traceroute to %s (%s), %i hops max %i byte packets\n", + result->ai_canonname, ip, 64, PACKETSIZE); + traceroute(result->ai_addr); + return (0); +} + diff --git a/traceroute/net.c b/traceroute/net.c new file mode 100644 index 00000000..475df20f --- /dev/null +++ b/traceroute/net.c @@ -0,0 +1,29 @@ +#include "traceroute.h" + +int host_format(struct sockaddr *addr) +{ + char dn[1024]; + char sv[20]; + char ip[INET_ADDRSTRLEN]; + + if (getnameinfo(addr, sizeof(*addr), dn, sizeof(dn), + sv, sizeof(sv), 0)) + { + perror("getnameinfo"); + return (1); + } + printf(" %s (%s)", dn, + inet_ntop(AF_INET, &(((struct sockaddr_in*)addr)->sin_addr), + ip, INET_ADDRSTRLEN)); + return (0); +} + +void ip_load_icmp(struct icmp *icmp, void *buf) +{ + struct ip *ip; + int hlen; + + ip = buf; + hlen = ip->ip_hl << 2; + memcpy(icmp, buf + hlen, sizeof(struct icmp)); +} diff --git a/traceroute/rs.c b/traceroute/rs.c new file mode 100644 index 00000000..9d4906ae --- /dev/null +++ b/traceroute/rs.c @@ -0,0 +1,61 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* rs.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/10/07 17:57:54 by jhalford #+# #+# */ +/* Updated: 2017/10/07 18:19:47 by jhalford ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "rs.h" +#include + +double sqrt(double x); + +void rs_init(t_rs *rs) +{ + bzero(rs, sizeof(t_rs)); + rs->count = 0; + rs->min = DBL_MAX; + rs->max = -DBL_MAX; +} + +void rs_push(t_rs *rs, double n) +{ + double delta; + + rs->count++; + n < rs->min ? rs->min = n : (0); + n > rs->max ? rs->max = n : (0); + if (rs->count == 1) + { + rs->avg = n; + rs->m = 0; + } + else + { + delta = n - rs->avg; + rs->avg += delta / rs->count; + rs->m += delta * (n - rs->avg); + } +} + +void rs_final(t_rs *rs) +{ + if (rs->count == 0) + { + rs->min = 0; + rs->max = 0; + } + if (rs->count < 2) + { + rs->var = 0; + rs->stdev = 0; + return ; + } + rs->var = rs->m / (rs->count - 1); + rs->stdev = sqrt(rs->var); +} diff --git a/traceroute/rs.h b/traceroute/rs.h new file mode 100644 index 00000000..3aa6bd6b --- /dev/null +++ b/traceroute/rs.h @@ -0,0 +1,34 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* rs.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/10/07 18:05:30 by jhalford #+# #+# */ +/* Updated: 2017/10/08 15:59:58 by jhalford ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#pragma once + +# include +# include +# include +# include + +typedef struct s_rs t_rs; + +struct s_rs { + int count; + double min; + double max; + double avg; + double m; + double stdev; + double var; +}; + +void rs_init(t_rs *rs); +void rs_push(t_rs *rs, double n); +void rs_final(t_rs *rs); diff --git a/traceroute/traceroute.c b/traceroute/traceroute.c new file mode 100644 index 00000000..643dcb78 --- /dev/null +++ b/traceroute/traceroute.c @@ -0,0 +1,111 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* main.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/04/22 14:10:24 by jhalford #+# #+# */ +/* Updated: 2017/10/08 17:55:05 by jhalford ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "traceroute.h" + +int g_pid; + +static int wait_for_reply(struct sockaddr *addr, unsigned char buf[1024]) +{ + static int sd;; + + sd = 0; + if (sd == 0) + { + if ((sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) + { + perror("socket"); + exit(1); + } + struct timeval tv; + tv.tv_sec = 5; + tv.tv_usec = 0; + setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, + (const char*)&tv, sizeof(struct timeval)); + } + bzero(buf, 1024); + return (recvfrom(sd, buf, 1024, 0, addr, NULL)); +} + +static int probe_once(int sd, struct sockaddr *addr, + struct s_packet *pkt, struct icmp *icmp) +{ + int bytes; + unsigned char buf[1024]; + double time; + + if (sendto(sd, &pkt, sizeof(pkt), 0, + addr, sizeof(*addr)) <= 0) + { + perror("sendto"); + exit(1); + } + time = time_milli(); + bytes = wait_for_reply(addr, buf); + time = time_milli() - time; + if (bytes < 0) + printf(" *"); + else + { + ip_load_icmp(icmp, buf); + printf(" %.3f ms", time); + } + return (0); +} + +static int probe_depth(int sd, struct sockaddr *addr, + struct s_packet pkt) +{ + struct icmp icmp; + int probe; + + probe = -1; + host_format(addr); + while (++probe < 3) + { + pkt.hdr.icmp_seq++; + pkt.hdr.icmp_cksum = cksum(&pkt, sizeof(pkt)); + probe_once(sd, addr, &pkt, &icmp); + } + printf("\n"); + return (icmp.icmp_type == ICMP_ECHOREPLY); +} + +void traceroute(struct sockaddr *addr) +{ + int sd; + int ttl; + struct s_packet pkt; + + if ((sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) + { + perror("socket"); + exit(1); + } + g_pid = getpid(); + bzero(&pkt, sizeof(pkt)); + pkt.hdr.icmp_type = ICMP_ECHO; + pkt.hdr.icmp_id = g_pid; + ttl = 0; + while (++ttl < 255) + { + printf("%2d ", ttl); + if (setsockopt(sd, 0, IP_TTL, &ttl, sizeof(ttl)) != 0) + { + perror("set TTL option"); + exit(1); + } + pkt.hdr.icmp_seq = (ttl - 1) * 3; + if (probe_depth(sd, addr, pkt)) + break ; + } +} diff --git a/traceroute/traceroute.h b/traceroute/traceroute.h new file mode 100644 index 00000000..aac77a69 --- /dev/null +++ b/traceroute/traceroute.h @@ -0,0 +1,46 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_ping.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/04/22 14:10:24 by jhalford #+# #+# */ +/* Updated: 2017/10/08 17:52:17 by jhalford ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#pragma once + +# include "error.h" +# include "cliopts.h" + +# include +# include + +# include +# include +# include + +# include +# include +# include +# include +# include +# include +# include +# include + +#define PACKETSIZE 56 + +struct s_packet +{ + struct icmp hdr; + char msg[PACKETSIZE - sizeof(struct icmp)]; +}; + +void traceroute(struct sockaddr *addr); +unsigned short cksum(void *b, int len); +int host_format(struct sockaddr *addr); +void ip_load_icmp(struct icmp *icmp, void *buf); +double time_milli(void);