1 /* -*- c-basic-offset: 8; -*-
3 * Copyright (c) 1993 W. Richard Stevens. All rights reserved.
4 * Permission to use or modify this software and its documentation only for
5 * educational purposes and without fee is hereby granted, provided that
6 * the above copyright notice appear in all copies. The author makes no
7 * representations about the suitability of this software for any purpose.
8 * It is provided "as is" without express or implied warranty.
13 #include <netinet/ip.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
19 * There is a fundamental limit of 9 IP addresses in a source route.
20 * But we allocate sroute_opt[44] with room for 10 IP addresses (and
21 * the 3-byte source route type/len/offset) because with the BSD
22 * IP_OPTIONS socket option we can specify up to 9 addresses, followed
23 * by the destination address. The in_pcbopts() function in the kernel
24 * then takes the final address in the list (the destination) and moves
25 * it to the front, as shown in Figure 9.33 of "TCP/IP Illustrated,
26 * Volume 2". Also note that this destination address that we pass as
27 * the final IP address in our array overrides the destination address
28 * of the sendto() (Figure 9.28 of Volume 2).
31 u_char sroute_opt
[44]; /* some implementations require this to be
32 on a 4-byte boundary */
33 u_char
*optr
; /* pointer into options being formed */
36 * Process either the -g (loose) or -G (strict) command-line option,
37 * specifying one hop in a source route.
38 * Either option can be specified up to 9 times.
39 * With IPv4 the entire source route is either loose or strict, but we
40 * set the source route type field based on the first option encountered,
45 sroute_doopt(int strict
, char *argptr
)
47 struct in_addr inaddr
;
51 err_quit("too many source routes with: %s", argptr
);
53 if (sroute_cnt
== 0) { /* first one */
54 bzero(sroute_opt
, sizeof(sroute_opt
));
56 *optr
++ = strict
? IPOPT_SSRR
: IPOPT_LSRR
;
57 optr
++; /* we fill in the total length later */
58 *optr
++ = 4; /* ptr to first source-route address */
61 if (inet_aton(argptr
, &inaddr
) == 1) {
62 bcopy(&inaddr
, optr
, sizeof(u_long
)); /* dotted decimal */
64 fprintf(stderr
, "source route to %s\n", inet_ntoa(inaddr
));
65 } else if ( (hp
= gethostbyname(argptr
)) != NULL
) {
66 bcopy(hp
->h_addr
, optr
, sizeof(u_long
));/* hostname */
68 fprintf(stderr
, "source route to %s\n",
69 inet_ntoa(*((struct in_addr
*) hp
->h_addr
)));
71 err_quit("unknown host: %s\n", argptr
);
73 optr
+= sizeof(u_long
); /* for next IP addr in list */
78 * Set the actual source route with the IP_OPTIONS socket option.
79 * This function is called if srouce_cnt is nonzero.
80 * The final destination goes at the end of the list of IP addresses.
84 sroute_set(int sockfd
)
86 sroute_cnt
++; /* account for destination */
87 sroute_opt
[1] = 3 + (sroute_cnt
* 4); /* total length, incl. destination */
89 /* destination must be stored as final entry */
90 bcopy(&servaddr
.sin_addr
, optr
, sizeof(u_long
));
91 optr
+= sizeof(u_long
);
93 fprintf(stderr
, "source route to %s\n", inet_ntoa(servaddr
.sin_addr
));
94 fprintf(stderr
, "source route size %d bytes\n", sroute_opt
[1]);
98 * The number of bytes that we pass to setsockopt() must be a multiple
99 * of 4. Since the buffer was initialized to 0, this leaves an EOL
100 * following the final IP address.
101 * For optimization we could put a NOP before the 3-byte type/len/offset
102 * field, which would then align all the IP addresses on 4-byte boundaries,
103 * but the source routing code is not exactly in the fast path of most
106 while ((optr
- sroute_opt
) & 3)
109 if (setsockopt(sockfd
, IPPROTO_IP
, IP_OPTIONS
,
110 sroute_opt
, optr
- sroute_opt
) < 0)
111 err_sys("setsockopt error for IP_OPTIONS");
113 sroute_cnt
= 0; /* don't call this function again */