summaryrefslogtreecommitdiffstats
path: root/tools/rpki-rov.c
blob: 4089a888076a6b5b9c1b7e973f8f943183af7c04 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
/*
 * This file is part of RTRlib.
 *
 * This file is subject to the terms and conditions of the MIT license.
 * See the file LICENSE in the top level directory for more details.
 *
 * Website: http://rtrlib.realmv6.org/
 */

#include "rtrlib/rtrlib.h"

#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

const int connection_timeout = 20;
enum rtr_mgr_status connection_status = -1;

static void connection_status_callback(const struct rtr_mgr_group *group __attribute__((unused)),
				       enum rtr_mgr_status status,
				       const struct rtr_socket *socket __attribute__((unused)),
				       void *data __attribute__((unused)))
{
	if (status == RTR_MGR_ERROR)
		connection_status = status;
}

static int connection_error(enum rtr_mgr_status status)
{
	if (status == RTR_MGR_ERROR) {
		/*
		 * Wait for input before printing error to avoid "broken pipe" error
		 * while communicating with the Python program.
		 */
		char input[256];

		if (fgets(input, 256, stdin))
			;
		printf("error\n");
		fflush(stdout);
		return 1;
	}
	return 0;
}

static int str_to_int(const char *str, int *value)
{
	errno = 0;
	int tmp = strtol(str, NULL, 10);

	if (errno != 0)
		return 1;

	*value = tmp;
	return 0;
}

int main(int argc, char *argv[])
{
	/* check arguments, need hostname/IP and port of cache-server */
	if (argc < 3) {
		printf("Usage: %s [host] [port]\n", argv[0]);
		return EXIT_FAILURE;
	}

	struct tr_socket tr_tcp;
	struct tr_tcp_config tcp_config = {argv[1], argv[2], NULL, NULL, NULL, 0};
	struct rtr_socket rtr_tcp;
	struct rtr_mgr_config *conf;
	struct rtr_mgr_group groups[1];

	/* init a TCP transport and create rtr socket */
	tr_tcp_init(&tcp_config, &tr_tcp);
	rtr_tcp.tr_socket = &tr_tcp;

	/* create a rtr_mgr_group array with 1 element */
	groups[0].sockets = malloc(1 * sizeof(struct rtr_socket *));
	groups[0].sockets_len = 1;
	groups[0].sockets[0] = &rtr_tcp;
	groups[0].preference = 1;

	if (rtr_mgr_init(&conf, groups, 1, 30, 600, 600, NULL, NULL, &connection_status_callback, NULL) < 0)
		return EXIT_FAILURE;

	rtr_mgr_start(conf);

	char input[256];
	int sleep_counter = 0;

	/* wait till at least one rtr_mgr_group is synchronized with server */
	while (!rtr_mgr_conf_in_sync(conf)) {
		if (connection_error(connection_status))
			return EXIT_FAILURE;

		sleep(1);
		sleep_counter++;
		if (sleep_counter >= connection_timeout) {
			/*
			 * Wait for input before printing "timeout",
			 * to avoid "broken pipee error while communicating
			 * with the Python program
			 */
			if (fgets(input, 256, stdin))
				;
			printf("timeout\n");
			fflush(stdout);
			return EXIT_FAILURE;
		}
	}

	int counter;
	/* loop for input */
	while (1) {
		int input_len;
		int spaces;

		/* recheck connection, exit on failure */
		if (connection_error(connection_status))
			return EXIT_FAILURE;

		/* try reading from stdin, exit on failure */
		if (!fgets(input, 256, stdin)) {
			printf("input error\n");
			return EXIT_FAILURE;
		}

		/* remove newline, if present */
		input_len = strlen(input) - 1;
		if (input[input_len] == '\n')
			input[input_len] = '\0';

		/* check if there are exactly 3 arguments */
		spaces = 0;
		for (counter = 0; counter < input_len; counter++) {
			if (input[counter] == ' ' && input[counter + 1] != ' ' && input[counter + 1] != '\0' &&
			    counter != 0)
				spaces++;
		}

		/* check input matching pattern */
		if (spaces != 2) {
			printf("Arguments required: IP Mask ASN\n");
			fflush(stdout);
			continue;
		}

		char delims[] = " ";
		char *input_tok = NULL;

		input_tok = strtok(input, delims);
		struct lrtr_ip_addr pref;
		char ip[INET6_ADDRSTRLEN];

		if (strlen(input_tok) > sizeof(ip) - 1) {
			fprintf(stderr, "Error: Invalid ip addr\n");
			continue;
		}

		memset(ip, 0, sizeof(ip));
		strncpy(ip, input_tok, sizeof(ip) - 1);

		if (lrtr_ip_str_to_addr(ip, &pref) != 0) {
			fprintf(stderr, "Error: Invalid ip addr\n");
			continue;
		}

		input_tok = strtok(NULL, delims);
		int mask;

		if (str_to_int(input_tok, &mask)) {
			fprintf(stderr, "Error: Invalid mask\n");
			continue;
		}

		input_tok = strtok(NULL, delims);
		int asn;

		if (str_to_int(input_tok, &asn)) {
			fprintf(stderr, "Error: Invalid asn\n");
			continue;
		}

		enum pfxv_state result;
		struct pfx_record *reason = NULL;
		unsigned int reason_len = 0;

		/* do validation */
		pfx_table_validate_r(groups[0].sockets[0]->pfx_table, &reason, &reason_len, asn, &pref, mask, &result);

		int validity_code = -1;
		/* translate validation result */
		if (result == BGP_PFXV_STATE_VALID)
			validity_code = 0;
		else if (result == BGP_PFXV_STATE_NOT_FOUND)
			validity_code = 1;
		else if (result == BGP_PFXV_STATE_INVALID)
			validity_code = 2;

		/* IP Mask BGP-ASN| */
		printf("%s %d %d|", ip, mask, asn);

		/* ROA-ASN IP MaskMin MaskMax, ... */
		if (reason && (reason_len > 0)) {
			unsigned int i;

			for (i = 0; i < reason_len; i++) {
				char tmp[100];

				lrtr_ip_addr_to_str(&reason[i].prefix, tmp, sizeof(tmp));
				printf("%u %s %u %u", reason[i].asn, tmp, reason[i].min_len, reason[i].max_len);
				if ((i + 1) < reason_len)
					printf(",");
			}
		}

		/* |validity_code */
		printf("|%d", validity_code);

		printf("\n");
		fflush(stdout);
	}

	rtr_mgr_stop(conf);
	rtr_mgr_free(conf);
	free(groups[0].sockets);

	return EXIT_SUCCESS;
}