3 * Copyright (c) 1994 Carnegie Mellon University
6 * See <cmu_copyright.h> for use and distribution information.
12 * Revision 1.1 2006/07/31 17:34:26 rra
13 * DELTA ka-forwarder-20060731
14 * AUTHOR rra@stanford.edu
18 * Revision 1.1 1997/06/03 18:23:54 kenh
21 * Revision 1.4 1996/08/09 01:00:21 jhutz
22 * When initializing the array of fakeka servers, remember to set
23 * the address family of each server; otherwise SunOS complains.
24 * [1996/08/09 00:58:46 jhutz]
26 * Revision 1.3 1996/08/09 00:17:19 jhutz
27 * Merged in changes from Chuck Silvers:
28 * - Support for more than one fakeka server
29 * - Support for specifying ports for each fakeka server separately from the
30 * others, and from the port we listen on.
32 * Plus a minor bug fix to Chuck's code.
33 * Basically, this version is designed to provide both reliability and
34 * load-balancing cheaply. Basically, we forward packets to all of the
35 * fakeka servers in round-robin fashion. So, if a client is losing on
36 * one server, its retry should go to a different one, if more than one
38 * [1996/08/03 02:13:36 jhutz]
40 * Revision 1.2 1995/02/23 18:26:36 chs
42 * [1995/02/23 18:26:03 chs]
48 * This program is intended to run on afs DB servers.
49 * Its function is to forward KA requests to a fakeka server
50 * running on an MIT kerberos server.
53 #include <sys/types.h>
54 #include <sys/socket.h>
55 #include <sys/ioctl.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
69 int getopt (int, char * const *, const char *);
74 #define BUFFER_SIZE 2048
79 int num_servers, cur_server;
80 struct sockaddr_in *servers;
93 setup_servers(argc, argv)
103 servers = malloc(sizeof(*servers) * num_servers);
105 perrorexit("malloc failed");
107 for (i = 0; i < num_servers; i++) {
110 fwdport = htons(7004);
113 port = strchr(host, '/');
117 if (isdigit(port[0])) {
118 fwdport = htons(atoi(port));
121 struct servent *srv = getservbyname(port, "udp");
123 fprintf(stderr, "%s: unknown service %s\n", prog, port);
126 fwdport = srv->s_port;
130 if (isdigit(host[0])) {
131 fwdaddr = inet_addr(host);
134 struct hostent *h = gethostbyname(host);
136 fprintf(stderr, "%s: unknown host %s\n", prog, host);
139 bcopy(h->h_addr, &fwdaddr, 4);
142 servers[i].sin_family = AF_INET;
143 servers[i].sin_addr.s_addr = fwdaddr;
144 servers[i].sin_port = fwdport;
154 struct sockaddr_in sin;
156 s = socket(AF_INET, SOCK_DGRAM, 0);
158 perrorexit("Couldn't create socket");
160 sin.sin_family = AF_INET;
161 sin.sin_addr.s_addr = 0;
162 sin.sin_port = htons(port);
164 rv = bind(s, (struct sockaddr *)&sin, sizeof(sin));
166 perrorexit("Couldn't bind socket");
173 packet_is_reply(from)
174 struct sockaddr_in *from;
178 for (i = 0; i < num_servers; i++) {
179 struct sockaddr_in *sin = &servers[i];
181 if (from->sin_addr.s_addr == sin->sin_addr.s_addr &&
182 from->sin_port == sin->sin_port)
202 "usage: %s [-p port] <host>[/port] [host/port ...]\n",
210 while ((c = getopt(argc, argv, "p:")) != -1) {
216 fprintf(stderr, "%s: invalid option '%c'\n", prog, c);
222 * hmm, different implementations of getopt seem to do different things
223 * when there aren't any options. linux sets optind = 1, which I would
224 * call correct, but sunos sets optind = 0. try to do the right thing.
229 setup_servers(argc - optind, argv + optind);
230 s = setup_socket(port);
232 openlog("ka-forwarder", LOG_PID, LOG_DAEMON);
235 char buf[BUFFER_SIZE], *bufp, *sendptr;
236 struct sockaddr_in from, reply, *to;
237 int fromlen, sendlen;
240 fromlen = sizeof(from);
242 rv = recvfrom(s, bufp, sizeof(buf) - 8,
243 0, (struct sockaddr *)&from, &fromlen);
245 syslog(LOG_ERR, "recvfrom: %m");
250 if (packet_is_reply(&from)) {
251 /* this is a reply, forward back to user */
254 reply.sin_family = AF_INET;
255 bcopy(bufp, &reply.sin_addr.s_addr, 4);
256 bcopy(bufp + 4, &reply.sin_port, 2);
261 /* this is a request, forward to server */
263 cur_server = (cur_server + 1) % num_servers;
264 to = &servers[cur_server];
266 bcopy(&from.sin_addr.s_addr, bufp - 8, 4);
267 bcopy(&from.sin_port, bufp - 4, 2);
275 strcpy(a1, inet_ntoa(from.sin_addr));
276 strcpy(a2, inet_ntoa(to->sin_addr));
278 syslog(LOG_INFO, "forwarding %d bytes from %s/%d to %s/%d\n",
279 sendlen, a1, htons(from.sin_port), a2, htons(to->sin_port));
282 rv = sendto(s, sendptr, sendlen,
283 0, (struct sockaddr *)to, sizeof(*to));
285 syslog(LOG_ERR, "sendto: %m");