1/* $FreeBSD: src/contrib/traceroute/as.c,v 1.1 2008/02/20 23:29:52 rpaulo Exp $ */
2/*	$NetBSD: as.c,v 1.1 2001/11/04 23:14:36 atatat Exp $	*/
3
4/*
5 * Copyright (c) 2001 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Andrew Brown.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *        This product includes software developed by the NetBSD
22 *        Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 *    contributors may be used to endorse or promote products derived
25 *    from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#include <sys/cdefs.h>
41#include <sys/types.h>
42#include <sys/socket.h>
43#include <netinet/in.h>
44#include <arpa/inet.h>
45#include <netdb.h>
46#include <unistd.h>
47#include <string.h>
48#include <stdlib.h>
49#include <errno.h>
50#include <err.h>
51#include <stdio.h>
52
53#include "as.h"
54
55#define DEFAULT_AS_SERVER "whois.radb.net"
56#undef AS_DEBUG_FILE
57
58struct aslookup {
59	FILE *as_f;
60#ifdef AS_DEBUG_FILE
61	FILE *as_debug;
62#endif /* AS_DEBUG_FILE */
63};
64
65void *
66as_setup(server)
67	char *server;
68{
69	struct aslookup *asn;
70	struct hostent *he = NULL;
71	struct servent *se;
72	struct sockaddr_in in;
73	FILE *f;
74	int s;
75
76	if (server == NULL)
77		server = DEFAULT_AS_SERVER;
78
79	(void)memset(&in, 0, sizeof(in));
80	in.sin_family = AF_INET;
81	in.sin_len = sizeof(in);
82	if ((se = getservbyname("whois", "tcp")) == NULL) {
83		warnx("warning: whois/tcp service not found");
84		in.sin_port = ntohs(43);
85	} else
86		in.sin_port = se->s_port;
87
88	if (inet_aton(server, &in.sin_addr) == 0 &&
89	    ((he = gethostbyname(server)) == NULL ||
90	    he->h_addr == NULL)) {
91		warnx("%s: %s", server, hstrerror(h_errno));
92		return (NULL);
93	}
94
95	if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
96		warn("socket");
97		return (NULL);
98	}
99
100	do {
101		if (he != NULL) {
102			memcpy(&in.sin_addr, he->h_addr, he->h_length);
103			he->h_addr_list++;
104		}
105		if (connect(s, (struct sockaddr *)&in, sizeof(in)) == 0)
106			break;
107		if (he == NULL || he->h_addr == NULL) {
108			close(s);
109			s = -1;
110			break;
111		}
112	} while (1);
113
114	if (s == -1) {
115		warn("connect");
116		return (NULL);
117	}
118
119	f = fdopen(s, "r+");
120	(void)fprintf(f, "!!\n");
121	(void)fflush(f);
122
123	asn = malloc(sizeof(struct aslookup));
124	if (asn == NULL)
125		(void)fclose(f);
126	else
127		asn->as_f = f;
128
129#ifdef AS_DEBUG_FILE
130	asn->as_debug = fopen(AS_DEBUG_FILE, "w");
131	if (asn->as_debug) {
132		(void)fprintf(asn->as_debug, ">> !!\n");
133		(void)fflush(asn->as_debug);
134	}
135#endif /* AS_DEBUG_FILE */
136
137	return (asn);
138}
139
140int
141as_lookup(_asn, addr)
142	void *_asn;
143	struct in_addr *addr;
144{
145	struct aslookup *asn = _asn;
146	char buf[1024];
147	int as, rc, dlen;
148
149	as = rc = dlen = 0;
150	(void)fprintf(asn->as_f, "!r%s/32,l\n", inet_ntoa(*addr));
151	(void)fflush(asn->as_f);
152
153#ifdef AS_DEBUG_FILE
154	if (asn->as_debug) {
155		(void)fprintf(asn->as_debug, ">> !r%s/32,l\n",
156		     inet_ntoa(*addr));
157		(void)fflush(asn->as_debug);
158	}
159#endif /* AS_DEBUG_FILE */
160
161	while (fgets(buf, sizeof(buf), asn->as_f) != NULL) {
162		buf[sizeof(buf) - 1] = '\0';
163
164#ifdef AS_DEBUG_FILE
165		if (asn->as_debug) {
166			(void)fprintf(asn->as_debug, "<< %s", buf);
167			(void)fflush(asn->as_debug);
168		}
169#endif /* AS_DEBUG_FILE */
170
171		if (rc == 0) {
172			rc = buf[0];
173			switch (rc) {
174			    case 'A':
175				/* A - followed by # bytes of answer */
176				sscanf(buf, "A%d\n", &dlen);
177#ifdef AS_DEBUG_FILE
178				if (asn->as_debug) {
179					(void)fprintf(asn->as_debug,
180					     "dlen: %d\n", dlen);
181					(void)fflush(asn->as_debug);
182				}
183#endif /* AS_DEBUG_FILE */
184				break;
185			    case 'C':
186			    case 'D':
187			    case 'E':
188			    case 'F':
189				/* C - no data returned */
190				/* D - key not found */
191				/* E - multiple copies of key */
192				/* F - some other error */
193				break;
194			}
195			if (rc == 'A')
196				/* skip to next input line */
197				continue;
198		}
199
200		if (dlen == 0)
201			/* out of data, next char read is end code */
202			rc = buf[0];
203		if (rc != 'A')
204			/* either an error off the bat, or a done code */
205			break;
206
207		/* data received, thank you */
208		dlen -= strlen(buf);
209
210		/* origin line is the interesting bit */
211		if (as == 0 && strncasecmp(buf, "origin:", 7) == 0) {
212			sscanf(buf + 7, " AS%d", &as);
213#ifdef AS_DEBUG_FILE
214			if (asn->as_debug) {
215				(void)fprintf(asn->as_debug, "as: %d\n", as);
216				(void)fflush(asn->as_debug);
217			}
218#endif /* AS_DEBUG_FILE */
219		}
220	}
221
222	return (as);
223}
224
225void
226as_shutdown(_asn)
227	void *_asn;
228{
229	struct aslookup *asn = _asn;
230
231	(void)fprintf(asn->as_f, "!q\n");
232	(void)fclose(asn->as_f);
233
234#ifdef AS_DEBUG_FILE
235	if (asn->as_debug) {
236		(void)fprintf(asn->as_debug, ">> !q\n");
237		(void)fclose(asn->as_debug);
238	}
239#endif /* AS_DEBUG_FILE */
240
241	free(asn);
242}
243