1 /* rapd.c -- Reverse APD, from ARS packet to APD string description.
2 * Copyright (C) 2003 Salvatore Sanfilippo
3 * All rights reserved. */
4
5 /* $Id: rapd.c,v 1.7 2004/04/10 00:45:11 antirez Exp $ */
6
7 #include <sys/types.h>
8 #include <netinet/in.h>
9 #include <ctype.h>
10
11 #include "ars.h"
12
trimlastchar(char * s)13 void trimlastchar(char *s)
14 {
15 int len = strlen(s);
16 s[len-1] = '\0';
17 }
18
ars_d_from_ars(char * dest,size_t len,struct ars_packet * pkt)19 int ars_d_from_ars(char *dest, size_t len, struct ars_packet *pkt)
20 {
21 int j, err;
22 struct adbuf buf;
23
24 if (len <= 0)
25 return -ARS_OK;
26 if (adbuf_init(&buf))
27 return -ARS_NOMEM;
28 for (j = 0; j < pkt->p_layer_nr; j++) {
29 __D(printf("ReverseAPD-ing layer %d\n", j);)
30 /* Skip NULL compilers */
31 if (ars_linfo[pkt->p_layer[j].l_type].li_rapd != NULL) {
32 /* Call the layer to string converter */
33 err = ars_linfo[pkt->p_layer[j].l_type].li_rapd(&buf, pkt, j);
34 if (err != -ARS_OK) {
35 adbuf_free(&buf);
36 return err;
37 }
38 }
39 }
40 adbuf_rtrim(&buf, 1);
41 strlcpy(dest, adbuf_ptr(&buf), len);
42 adbuf_free(&buf);
43 return -ARS_OK;
44 }
45
46 /* layer rapd methods */
ars_rapd_ip(struct adbuf * dest,struct ars_packet * pkt,int layer)47 int ars_rapd_ip(struct adbuf *dest, struct ars_packet *pkt, int layer)
48 {
49 struct ars_iphdr *ip = pkt->p_layer[layer].l_data;
50 struct ars_iphdr *defip = pkt->p_default[pkt->p_layer[layer].l_type];
51 adbuf_printf(dest, "ip(");
52 if (!defip || ip->ihl != defip->ihl)
53 adbuf_printf(dest, "ihl=0x%1x,", ip->ihl);
54 if (!defip || ip->version != defip->version)
55 adbuf_printf(dest, "ver=0x%1x,", ip->version);
56 if (!defip || ip->tos != defip->tos)
57 adbuf_printf(dest, "tos=0x%02x,", ip->tos);
58 adbuf_printf(dest, "totlen=%u,", ntohs(ip->tot_len));
59 if (!defip || ip->id != defip->id)
60 adbuf_printf(dest, "id=%u,", ntohs(ip->id));
61 adbuf_printf(dest, "fragoff=%u,",
62 (ntohs(ip->frag_off) & 0x1FFF) << 3);
63 if (!defip ||
64 (ip->frag_off & ARS_IP_MF) != (defip->frag_off & ARS_IP_MF))
65 adbuf_printf(dest, "mf=%d,",
66 (htons(ip->frag_off) & ARS_IP_MF) != 0);
67 if (!defip ||
68 (ip->frag_off & ARS_IP_DF) != (defip->frag_off & ARS_IP_DF))
69 adbuf_printf(dest, "df=%d,",
70 (htons(ip->frag_off) & ARS_IP_DF) != 0);
71 if (!defip ||
72 (ip->frag_off & ARS_IP_RF) != (defip->frag_off & ARS_IP_RF))
73 adbuf_printf(dest, "rf=%d,",
74 (htons(ip->frag_off) & ARS_IP_RF) != 0);
75 if (!defip || ip->ttl != defip->ttl)
76 adbuf_printf(dest, "ttl=%u,", ip->ttl);
77 /* TODO: the 'proto' field may not be added if the protocl
78 * that follows this layer looks as specified. */
79 adbuf_printf(dest, "proto=%u,", ip->protocol);
80 adbuf_printf(dest, "cksum=0x%04x,", ip->check);
81 {
82 unsigned char *x = (unsigned char*) &ip->saddr;
83 adbuf_printf(dest, "saddr=%u.%u.%u.%u,",
84 x[0], x[1], x[2], x[3]);
85 x = (unsigned char*) &ip->daddr;
86 adbuf_printf(dest, "daddr=%u.%u.%u.%u",
87 x[0], x[1], x[2], x[3]);
88 }
89 adbuf_printf(dest, ")+");
90 return -ARS_OK;
91 }
92
ars_rapd_ipopt(struct adbuf * dest,struct ars_packet * pkt,int layer)93 int ars_rapd_ipopt(struct adbuf *dest, struct ars_packet *pkt, int layer)
94 {
95 struct ars_ipopt ipopt;
96 int len = pkt->p_layer[layer].l_size;
97 unsigned char *optp = pkt->p_layer[layer].l_data;
98 int optlen, i;
99
100 /* ip options may not be naturally aligned */
101 memcpy(&ipopt, pkt->p_layer[layer].l_data, len);
102 optlen = ipopt.len;
103
104 switch(ipopt.kind) {
105 case ARS_IPOPT_EOL:
106 adbuf_printf(dest, "ip.eol()+");
107 break;
108 case ARS_IPOPT_NOP:
109 adbuf_printf(dest, "ip.nop()+");
110 break;
111 case ARS_IPOPT_RR:
112 case ARS_IPOPT_LSRR:
113 case ARS_IPOPT_SSRR:
114 {
115 int ptr = 4;
116 char *optname = "";
117
118 switch(ipopt.kind) {
119 case ARS_IPOPT_RR: optname="rr"; break;
120 case ARS_IPOPT_LSRR: optname="lsrr"; break;
121 case ARS_IPOPT_SSRR: optname="ssrr"; break;
122 }
123 adbuf_printf(dest, "ip.%s(ptr=%u,data=",
124 optname, ipopt.un.rr.ptr);
125 while(1) {
126 unsigned char *x;
127
128 if (ptr > 37 ||
129 ptr > (optlen-3))
130 break;
131 x = optp + ptr - 1;
132 adbuf_printf(dest, "%u.%u.%u.%u/",
133 x[0],x[1],x[2],x[3]);
134 ptr += 4;
135 }
136 if (ptr > 4)
137 adbuf_rtrim(dest, 1);
138 adbuf_printf(dest, ")+");
139 }
140 break;
141 case ARS_IPOPT_TIMESTAMP:
142 {
143 int ptr = 5;
144 int overflow = (ipopt.un.ts.flags & 0xF0)>>4;
145 int flags = ipopt.un.ts.flags & 0xF;
146 char *strflags;
147 adbuf_printf(dest, "ip.ts(ptr=%u,", ipopt.un.ts.ptr);
148 switch(flags) {
149 case ARS_IPOPT_TS_TSONLY: strflags="tsonly"; break;
150 case ARS_IPOPT_TS_TSANDADDR: strflags="tsandaddr"; break;
151 case ARS_IPOPT_TS_PRESPEC: strflags="prespec"; break;
152 default: strflags=NULL; break;
153 }
154 if (strflags) {
155 adbuf_printf(dest, "flags=%s,", strflags);
156 } else {
157 adbuf_printf(dest, "flags=%u,", flags);
158 }
159 adbuf_printf(dest, "overflow=%u,data=", overflow);
160 while(1) {
161 unsigned char *x;
162 __u32 ts;
163
164 if (ptr > 37 ||
165 ptr > (optlen-4))
166 break;
167 if (flags != ARS_IPOPT_TS_TSANDADDR &&
168 flags != ARS_IPOPT_TS_PRESPEC) {
169 memcpy(&ts, optp+ptr-1, 4);
170 ts = ntohl(ts);
171 adbuf_printf(dest, "%u/", ts);
172 ptr += 4;
173 } else {
174 x = optp + ptr - 1;
175 memcpy(&ts, x+4, 4);
176 adbuf_printf(dest, "%u@%u.%u.%u.%u/",
177 ts,x[0],x[1],x[2],x[3]);
178 ptr += 8;
179 }
180 }
181 if (ptr > 5)
182 adbuf_rtrim(dest, 1);
183 adbuf_printf(dest, ")+");
184 }
185 break;
186 default:
187 adbuf_printf(dest, "ip.unknown(hex=");
188 for (i = 0; i < optlen; i++) {
189 adbuf_printf(dest, "0x%02x", optp[i]);
190 }
191 adbuf_printf(dest, ")+");
192 break;
193 }
194 return -ARS_OK;
195 }
196
ars_rapd_icmp(struct adbuf * dest,struct ars_packet * pkt,int layer)197 int ars_rapd_icmp(struct adbuf *dest, struct ars_packet *pkt, int layer)
198 {
199 struct ars_icmphdr *icmp = pkt->p_layer[layer].l_data;
200
201 adbuf_printf(dest, "icmp(");
202 adbuf_printf(dest, "type=%u,", icmp->type);
203 adbuf_printf(dest, "code=%u,", icmp->code);
204 if (icmp->type == ARS_ICMP_DEST_UNREACH ||
205 icmp->type == ARS_ICMP_TIME_EXCEEDED ||
206 icmp->type == ARS_ICMP_PARAMETERPROB ||
207 icmp->type == ARS_ICMP_SOURCE_QUENCH)
208 {
209 adbuf_printf(dest, "unused=%lu,", (unsigned long)
210 ntohl(icmp->un.gateway));
211 }
212 if (icmp->type == ARS_ICMP_ECHOREPLY ||
213 icmp->type == ARS_ICMP_ECHO ||
214 icmp->type == ARS_ICMP_TIMESTAMP ||
215 icmp->type == ARS_ICMP_TIMESTAMPREPLY ||
216 icmp->type == ARS_ICMP_INFO_REQUEST ||
217 icmp->type == ARS_ICMP_INFO_REPLY)
218 {
219 adbuf_printf(dest, "id=%u,", ntohs(icmp->un.echo.id));
220 adbuf_printf(dest, "seq=%u,", ntohs(icmp->un.echo.sequence));
221 }
222 if (icmp->type == ARS_ICMP_REDIRECT) {
223 unsigned char x[4];
224 memcpy(x, &icmp->un.gateway, 4);
225 adbuf_printf(dest, "gw=%u.%u.%u.%u,",
226 x[0], x[1], x[2], x[3]);
227 }
228 adbuf_rtrim(dest, 1);
229 adbuf_printf(dest, ")+");
230 return -ARS_OK;
231 }
232
ars_rapd_udp(struct adbuf * dest,struct ars_packet * pkt,int layer)233 int ars_rapd_udp(struct adbuf *dest, struct ars_packet *pkt, int layer)
234 {
235 struct ars_udphdr *udp = pkt->p_layer[layer].l_data;
236 //struct ars_udphdr *defudp = pkt->p_default[pkt->p_layer[layer].l_type];
237 adbuf_printf(dest, "udp(");
238 adbuf_printf(dest, "sport=%u,", ntohs(udp->uh_sport));
239 adbuf_printf(dest, "dport=%u,", ntohs(udp->uh_dport));
240 adbuf_printf(dest, "len=%u,", ntohs(udp->uh_ulen));
241 adbuf_printf(dest, "cksum=0x%04x", ntohs(udp->uh_sum));
242 adbuf_printf(dest, ")+");
243 return -ARS_OK;
244 }
245
ars_rapd_tcp(struct adbuf * dest,struct ars_packet * pkt,int layer)246 int ars_rapd_tcp(struct adbuf *dest, struct ars_packet *pkt, int layer)
247 {
248 struct ars_tcphdr *tcp = pkt->p_layer[layer].l_data;
249 struct ars_tcphdr *deftcp = pkt->p_default[pkt->p_layer[layer].l_type];
250 adbuf_printf(dest, "tcp(");
251 adbuf_printf(dest, "sport=%u,", ntohs(tcp->th_sport));
252 adbuf_printf(dest, "dport=%u,", ntohs(tcp->th_dport));
253 adbuf_printf(dest, "seq=%lu,", ntohl(tcp->th_seq));
254 adbuf_printf(dest, "ack=%lu,", ntohl(tcp->th_ack));
255 if (!deftcp || tcp->th_x2 != deftcp->th_x2)
256 adbuf_printf(dest, "x2=0x%1x,", tcp->th_x2);
257 if (!deftcp || tcp->th_off != deftcp->th_off)
258 adbuf_printf(dest, "off=%u,", tcp->th_off);
259 adbuf_printf(dest, "flags=");
260 if (tcp->th_flags & ARS_TCP_TH_FIN) adbuf_printf(dest, "f");
261 if (tcp->th_flags & ARS_TCP_TH_SYN) adbuf_printf(dest, "s");
262 if (tcp->th_flags & ARS_TCP_TH_RST) adbuf_printf(dest, "r");
263 if (tcp->th_flags & ARS_TCP_TH_PUSH) adbuf_printf(dest, "p");
264 if (tcp->th_flags & ARS_TCP_TH_ACK) adbuf_printf(dest, "a");
265 if (tcp->th_flags & ARS_TCP_TH_URG) adbuf_printf(dest, "u");
266 if (tcp->th_flags & ARS_TCP_TH_X) adbuf_printf(dest, "x");
267 if (tcp->th_flags & ARS_TCP_TH_Y) adbuf_printf(dest, "y");
268 adbuf_printf(dest, ",");
269 adbuf_printf(dest, "win=%u,", ntohs(tcp->th_win));
270 adbuf_printf(dest, "cksum=0x%04x,", ntohs(tcp->th_sum));
271 if (!deftcp || tcp->th_urp != deftcp->th_urp)
272 adbuf_printf(dest, "urp=%u,", ntohs(tcp->th_urp));
273 adbuf_rtrim(dest, 1);
274 adbuf_printf(dest, ")+");
275 return -ARS_OK;
276 }
277
ars_rapd_tcpopt(struct adbuf * dest,struct ars_packet * pkt,int layer)278 int ars_rapd_tcpopt(struct adbuf *dest, struct ars_packet *pkt, int layer)
279 {
280 struct ars_tcpopt tcpopt;
281 int len = pkt->p_layer[layer].l_size;
282 unsigned char *optp = pkt->p_layer[layer].l_data;
283 int optlen, i;
284
285 /* tcp options may not be naturally aligned */
286 memcpy(&tcpopt, pkt->p_layer[layer].l_data, len);
287 optlen = tcpopt.len;
288
289 switch(tcpopt.kind) {
290 case ARS_TCPOPT_EOL:
291 adbuf_printf(dest, "tcp.eol()+");
292 break;
293 case ARS_TCPOPT_NOP:
294 adbuf_printf(dest, "tcp.nop()+");
295 break;
296 case ARS_TCPOPT_MAXSEG:
297 adbuf_printf(dest, "tcp.mss(size=%u)+",
298 ntohs(tcpopt.un.mss.size));
299 break;
300 case ARS_TCPOPT_WINDOW:
301 adbuf_printf(dest, "tcp.wscale(shift=%u)+",
302 tcpopt.un.win.shift);
303 break;
304 case ARS_TCPOPT_SACK_PERM:
305 adbuf_printf(dest, "tcp.sackperm()+");
306 break;
307 case ARS_TCPOPT_SACK:
308 adbuf_printf(dest, "tcp.sack(blocks=");
309 {
310 int blocks = (optlen-2)/8;
311 for (i = 0; i < blocks; i++) {
312 u_int32_t s_orig, s_size;
313
314 memcpy(&s_orig, tcpopt.un.sack[i].origin, 4);
315 memcpy(&s_size, tcpopt.un.sack[i].size, 4);
316 adbuf_printf(dest, "%lu-%lu",
317 ntohl(s_orig),
318 ntohl(s_size));
319 if ((i+1) != blocks)
320 adbuf_addchar(dest, '/');
321 }
322 }
323 adbuf_printf(dest, ")+");
324 break;
325 case ARS_TCPOPT_ECHOREQUEST:
326 {
327 __u32 info;
328 memcpy(&info, tcpopt.un.echo.info, 4);
329 adbuf_printf(dest, "tcp.echoreq(info=%lu)+",
330 (unsigned long) ntohl(info));
331 }
332 break;
333 case ARS_TCPOPT_ECHOREPLY:
334 {
335 __u32 info;
336 memcpy(&info, tcpopt.un.echo.info, 4);
337 adbuf_printf(dest, "tcp.echoreply(info=%lu)+",
338 (unsigned long) ntohl(info));
339 }
340 break;
341 case ARS_TCPOPT_TIMESTAMP:
342 {
343 __u32 tsval, tsecr;
344 memcpy(&tsval, tcpopt.un.timestamp.tsval, 4);
345 memcpy(&tsecr, tcpopt.un.timestamp.tsecr, 4);
346 adbuf_printf(dest, "tcp.timestamp(val=%lu,ecr=%lu)+",
347 (unsigned long) ntohl(tsval),
348 (unsigned long) ntohl(tsecr));
349 }
350 break;
351 default:
352 adbuf_printf(dest, "tcp.unknown(hex=");
353 for (i = 0; i < optlen; i++) {
354 adbuf_printf(dest, "%02x", optp[i]);
355 }
356 adbuf_printf(dest, ")+");
357 break;
358 }
359 return -ARS_OK;
360 }
361
ars_rapd_igrp(struct adbuf * dest,struct ars_packet * pkt,int layer)362 int ars_rapd_igrp(struct adbuf *dest, struct ars_packet *pkt, int layer)
363 {
364 struct ars_igrphdr *igrp = pkt->p_layer[layer].l_data;
365
366 adbuf_printf(dest, "igrp(");
367 adbuf_printf(dest, "version=%u,", igrp->version);
368 if (igrp->opcode == ARS_IGRP_OPCODE_UPDATE) {
369 adbuf_printf(dest, "opcode=update,", igrp->opcode);
370 } else if (igrp->opcode == ARS_IGRP_OPCODE_REQUEST) {
371 adbuf_printf(dest, "opcode=request,", igrp->opcode);
372 } else {
373 adbuf_printf(dest, "opcode=%u,", igrp->opcode);
374 }
375 adbuf_printf(dest, "edition=%u,", igrp->edition);
376 adbuf_printf(dest, "autosys=%u,", htons(igrp->autosys));
377 adbuf_printf(dest, "interior=%u,", htons(igrp->interior));
378 adbuf_printf(dest, "system=%u,", htons(igrp->system));
379 adbuf_printf(dest, "exterior=%u,", htons(igrp->exterior));
380 adbuf_printf(dest, "cksum=0x%04x", ntohs(igrp->checksum));
381 adbuf_printf(dest, ")+");
382 return -ARS_OK;
383 }
384
get_net_int24(void * ptr)385 static u_int32_t get_net_int24(void *ptr)
386 {
387 unsigned char *x = (unsigned char*)ptr;
388 u_int32_t u;
389
390 u = x[0] <<16 | x[1] << 8 | x[2];
391 return u;
392 }
393
ars_rapd_igrpentry(struct adbuf * dest,struct ars_packet * pkt,int layer)394 int ars_rapd_igrpentry(struct adbuf *dest, struct ars_packet *pkt, int layer)
395 {
396 struct ars_igrpentry *entry = pkt->p_layer[layer].l_data;
397 unsigned char *x = (unsigned char*) entry->destination;
398
399 adbuf_printf(dest, "igrp.entry(");
400 adbuf_printf(dest, "dest=%u.%u.%u,", x[0], x[1], x[2]);
401 adbuf_printf(dest, "delay=%u,", get_net_int24(entry->delay));
402 adbuf_printf(dest, "bandwidth=%u,", get_net_int24(entry->bandwidth));
403 adbuf_printf(dest, "mtu=%u,", entry->mtu[0] << 8 | entry->mtu[1]);
404 adbuf_printf(dest, "reliability=%u,", entry->reliability);
405 adbuf_printf(dest, "load=%u,", entry->load);
406 adbuf_printf(dest, "hopcount=%u", entry->hopcount);
407 adbuf_printf(dest, ")+");
408 return -ARS_OK;
409 }
410
ars_rapd_data(struct adbuf * dest,struct ars_packet * pkt,int layer)411 int ars_rapd_data(struct adbuf *dest, struct ars_packet *pkt, int layer)
412 {
413 unsigned char *data = pkt->p_layer[layer].l_data;
414 int dlen = pkt->p_layer[layer].l_size, i;
415
416 if (ars_test_option(pkt, ARS_OPT_RAPD_HEXDATA)) {
417 adbuf_printf(dest, "data(hex=");
418 for (i = 0; i < dlen; i++) {
419 adbuf_printf(dest, "%02x", data[i]);
420 }
421 adbuf_printf(dest, ")+");
422 } else {
423 adbuf_printf(dest, "data(str=");
424 for (i = 0; i < dlen; i++) {
425 /* escape non-printable chars and chars
426 * having special meanings in APD packets. */
427 if (isgraph(data[i]) &&
428 data[i] != '(' &&
429 data[i] != ')' &&
430 data[i] != '+' &&
431 data[i] != ',' &&
432 data[i] != '=')
433 adbuf_printf(dest, "%c", data[i]);
434 else
435 adbuf_printf(dest, "\\%02x", data[i]);
436 }
437 adbuf_printf(dest, ")+");
438 }
439 return 0;
440 }
441