-
Notifications
You must be signed in to change notification settings - Fork 19
/
rip.c
132 lines (124 loc) · 4.3 KB
/
rip.c
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
/* rip.c - RIP-1 and -2 code for sendip
* Taken from code by Richard Polton <Richard.Polton@msdw.com>
* ChangeLog since 2.0 release:
* 02/12/2001 Only check 1 layer for enclosing UDP header
* 21/08/2002 Off-by-one fix in -re handling that caused bad things to happen
* 21/08/2002 htons() and htonl() added where needed
* ChangeLog since 2.2 release:
* 24/11/2002 make it compile on archs that care about alignment
* ChangeLog since 2.5 release:
* 26/10/2004 fix bug with multiple -re options (found by several people)
* 28/10/2004 fix -ra (thanks to sharmily.anantaraman@conexant.com)
*/
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include "sendip_module.h"
#include "rip.h"
/* Character that identifies our options
*/
const char opt_char='r';
sendip_data *initialize(void) {
sendip_data *ret = malloc(sizeof(sendip_data));
rip_header *rip = malloc(sizeof(rip_header));
memset(rip,0,sizeof(rip_header));
ret->alloc_len = sizeof(rip_header);
ret->data = (void *)rip;
ret->modified=0;
return ret;
}
bool do_opt(char *opt, char *arg, sendip_data *pack) {
rip_header *rippack = (rip_header *)pack->data;
rip_options *ripopt;
char *p, *q;
switch(opt[1]) {
case 'v': /* version */
rippack->version = (u_int8_t)strtoul(arg, (char **)0, 0);
pack->modified |= RIP_MOD_VERSION;
break;
case 'c': /* command */
rippack->command = (u_int8_t)strtoul(arg, (char **)0, 0);
pack->modified |= RIP_MOD_COMMAND;
break;
case 'a': /* authenticate */
if(RIP_NUM_ENTRIES(pack) != 0) {
usage_error("Warning: a real RIP-2 packet only has authentication as the first entry.\n");
}
RIP_ADD_ENTRY(pack);
ripopt = RIP_OPTION(pack);
memset(ripopt,0,sizeof(rip_options));
ripopt->addressFamily=0xFFFF;
p=q=arg;
/* TODO: if arg is malformed, this could segfault */
while(*(q++)!=':') {} /* do nothing */; *(--q)='\0';
ripopt->routeTagOrAuthenticationType=htons((p==q)?2:(u_int16_t)strtoul(p, (char **)0,0));
p=++q;
if(strlen(p) > 16) {
usage_error("Warning: RIP passord cannot be longer than 16 characters.\n");
}
strncpy((char *)&(ripopt->address),p,16);
break;
case 'e': /* rip entry */
if(RIP_NUM_ENTRIES(pack)==25) {
usage_error("Warning: a real RIP packet contains no more than 25 entries.\n");
}
RIP_ADD_ENTRY(pack);
ripopt = RIP_OPTION(pack);
p=q=arg;
/* TODO: if arg is malformed, this could segfault */
while(*(q++)!=':') {} /* do nothing */; *(--q)='\0';
ripopt->addressFamily= htons((p==q)?2:(u_int16_t)strtoul(p, (char **)0, 0));
p=++q; while(*(q++)!=':') {} /* do nothing */; *(--q)='\0';
ripopt->routeTagOrAuthenticationType=htons((p==q)?0:(u_int16_t)strtoul(p, (char **)0,0));
p=++q; while(*(q++)!=':') {} /* do nothing */; *(--q)='\0';
ripopt->address=(p==q)?inet_addr("0.0.0.0"):inet_addr(p);
p=++q; while(*(q++)!=':') {} /* do nothing */; *(--q)='\0';
ripopt->subnetMask=(p==q)?inet_addr("255.255.255.0"):inet_addr(p);
p=++q; while(*(q++)!=':') {} /* do nothing */; *(--q)='\0';
ripopt->nextHop=(p==q)?inet_addr("0.0.0.0"):inet_addr(p);
p=++q; while(*(q++)!='\0') {} /* do nothing */; *(--q)='\0';
ripopt->metric=htonl((p==q)?16:(u_int32_t)strtoul(p,(char **)0, 0));
break;
case 'd': /* default request */
if(RIP_NUM_ENTRIES(pack) != 0) {
usage_error("Warning: a real RIP-1 or -2 packet does not have any entries in a default request.\n");
}
RIP_ADD_ENTRY(pack);
ripopt=RIP_OPTION(pack);
rippack->command = (u_int8_t)1;
ripopt->addressFamily = (u_int16_t)0;
ripopt->routeTagOrAuthenticationType = (u_int16_t)0;
ripopt->address=inet_addr("0.0.0.0");
ripopt->subnetMask=inet_addr("0.0.0.0");
ripopt->nextHop=inet_addr("0.0.0.0");
ripopt->metric=htons((u_int16_t)16);
break;
case 'r': /* set reserved field */
rippack->res = (u_int16_t)strtoul(arg, (char **)0, 0);
pack->modified |= RIP_MOD_RESERVED;
break;
default:
usage_error("Unrecognized option opt");
return FALSE;
}
return TRUE;
}
bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data,
sendip_data *pack) {
if(hdrs[strlen(hdrs)-1] != 'u') {
usage_error("Warning: RIP should be contained in a UDP packet\n");
}
return TRUE;
}
int num_opts() {
return sizeof(rip_opts)/sizeof(sendip_option);
}
sendip_option *get_opts() {
return rip_opts;
}
char get_optchar() {
return opt_char;
}