1 /*
2  * This file is part of RTRlib.
3  *
4  * This file is subject to the terms and conditions of the MIT license.
5  * See the file LICENSE in the top level directory for more details.
6  *
7  * Website: http://rtrlib.realmv6.org/
8  */
9 
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include "rtrlib/rtrlib.h"
15 
16 const int connection_timeout = 20;
17 enum rtr_mgr_status connection_status = -1;
18 
connection_status_callback(const struct rtr_mgr_group * group,enum rtr_mgr_status status,const struct rtr_socket * socket,void * data)19 static void connection_status_callback(const struct rtr_mgr_group *group,
20 				       enum rtr_mgr_status status,
21 				       const struct rtr_socket *socket,
22 				       void *data)
23 {
24 	if (status == RTR_MGR_ERROR)
25 		connection_status = status;
26 }
27 
connection_error(enum rtr_mgr_status status)28 int connection_error(enum rtr_mgr_status status)
29 {
30 	if (status == RTR_MGR_ERROR) {
31 	/*
32 	 * Wait for input before printing error to avoid "broken pipe" error
33 	 * while communicating with the Python program.
34 	 */
35 		char input[256];
36 
37 		if (fgets(input, 256, stdin))
38 			;
39 		printf("error\n");
40 		fflush(stdout);
41 		return 1;
42 	}
43 	return 0;
44 }
45 
main(int argc,char * argv[])46 int main(int argc, char *argv[])
47 {
48 	/* check arguments, need hostname/IP and port of cache-server */
49 	if (argc < 3) {
50 		printf("Usage: %s [host] [port]\n", argv[0]);
51 		return EXIT_FAILURE;
52 	}
53 
54 	struct tr_socket tr_tcp;
55 	struct tr_tcp_config tcp_config = { argv[1], argv[2], NULL };
56 	struct rtr_socket rtr_tcp;
57 	struct rtr_mgr_config *conf;
58 	struct rtr_mgr_group groups[1];
59 
60 	/* init a TCP transport and create rtr socket */
61 	tr_tcp_init(&tcp_config, &tr_tcp);
62 	rtr_tcp.tr_socket = &tr_tcp;
63 
64 	/* create a rtr_mgr_group array with 1 element */
65 	groups[0].sockets = malloc(1 * sizeof(struct rtr_socket *));
66 	groups[0].sockets_len = 1;
67 	groups[0].sockets[0] = &rtr_tcp;
68 	groups[0].preference = 1;
69 
70 	if (rtr_mgr_init(&conf, groups, 1, 30, 600, 600, NULL, NULL,
71 			 &connection_status_callback, NULL) < 0)
72 		return EXIT_FAILURE;
73 
74 	rtr_mgr_start(conf);
75 
76 	char input[256];
77 	int sleep_counter = 0;
78 
79 	/* wait till at least one rtr_mgr_group is synchronized with server */
80 	while (!rtr_mgr_conf_in_sync(conf)) {
81 		if (connection_error(connection_status))
82 			return EXIT_FAILURE;
83 
84 		sleep(1);
85 		sleep_counter++;
86 		if (sleep_counter >= connection_timeout) {
87 			/*
88 			 * Wait for input before printing "timeout",
89 			 * to avoid "broken pipee error while communicating
90 			 * with the Python program
91 			 */
92 			if (fgets(input, 256, stdin))
93 				;
94 			printf("timeout\n");
95 			fflush(stdout);
96 			return EXIT_FAILURE;
97 		}
98 	}
99 
100 	char ip[128];
101 	int mask;
102 	int asn;
103 	int counter;
104 	/* loop for input */
105 	while (1) {
106 		int input_len;
107 		int spaces;
108 
109 		/* recheck connection, exit on failure */
110 		if (connection_error(connection_status))
111 			return EXIT_FAILURE;
112 
113 		/* try reading from stdin, exit on failure */
114 		if (!fgets(input, 256, stdin)) {
115 			printf("input error\n");
116 			return EXIT_FAILURE;
117 		}
118 
119 		/* remove newline, if present */
120 		input_len = strlen(input) - 1;
121 		if (input[input_len] == '\n')
122 			input[input_len] = '\0';
123 
124 		/* check if there are exactly 3 arguments */
125 		spaces = 0;
126 		for (counter = 0; counter < input_len; counter++) {
127 			if (input[counter] == ' ' &&
128 			    input[counter + 1] != ' ' &&
129 			    input[counter + 1] != '\0' && counter != 0)
130 				spaces++;
131 		}
132 
133 		/* check input matching pattern */
134 		if (spaces != 2) {
135 			printf("Arguments required: IP Mask ASN\n");
136 			fflush(stdout);
137 			continue;
138 		}
139 
140 		char delims[] = " ";
141 		char *input_tok = NULL;
142 
143 		input_tok = strtok(input, delims);
144 		strcpy(ip, input_tok);
145 		input_tok = strtok(NULL, delims);
146 		mask = atoi(input_tok);
147 		input_tok = strtok(NULL, delims); asn = atoi(input_tok);
148 
149 		struct lrtr_ip_addr pref;
150 		enum pfxv_state result;
151 		struct pfx_record *reason = NULL;
152 		unsigned int reason_len = 0;
153 
154 		lrtr_ip_str_to_addr(ip, &pref);
155 		/* do validation */
156 		pfx_table_validate_r(groups[0].sockets[0]->pfx_table, &reason,
157 				     &reason_len, asn, &pref, mask, &result);
158 
159 		int validity_code = -1;
160 		/* translate validation result */
161 		if (result == BGP_PFXV_STATE_VALID)
162 			validity_code = 0;
163 		else if (result == BGP_PFXV_STATE_NOT_FOUND)
164 			validity_code = 1;
165 		else if (result == BGP_PFXV_STATE_INVALID)
166 			validity_code = 2;
167 
168 		/* IP Mask BGP-ASN| */
169 		printf("%s %d %d|", ip, mask, asn);
170 
171 		/* ROA-ASN IP MaskMin MaskMax, ... */
172 		if (reason && (reason_len > 0)) {
173 			unsigned int i;
174 
175 			for (i = 0; i < reason_len; i++) {
176 				char tmp[100];
177 
178 				lrtr_ip_addr_to_str(&reason[i].prefix,
179 						    tmp, sizeof(tmp));
180 				printf("%u %s %u %u",
181 				       reason[i].asn, tmp,
182 				       reason[i].min_len,
183 				       reason[i].max_len);
184 				if ((i + 1) < reason_len)
185 					printf(",");
186 			}
187 		}
188 
189 		/* |validity_code */
190 		printf("|%d", validity_code);
191 
192 		printf("\n");
193 		fflush(stdout);
194 	}
195 
196 	rtr_mgr_stop(conf);
197 	rtr_mgr_free(conf);
198 	free(groups[0].sockets);
199 
200 	return EXIT_SUCCESS;
201 }
202