1176428Srpaulo/* $FreeBSD$ */
2176428Srpaulo/*	$NetBSD: as.c,v 1.1 2001/11/04 23:14:36 atatat Exp $	*/
3176428Srpaulo
4176428Srpaulo/*
5176428Srpaulo * Copyright (c) 2001 The NetBSD Foundation, Inc.
6176428Srpaulo * All rights reserved.
7176428Srpaulo *
8176428Srpaulo * This code is derived from software contributed to The NetBSD Foundation
9176428Srpaulo * by Andrew Brown.
10176428Srpaulo *
11176428Srpaulo * Redistribution and use in source and binary forms, with or without
12176428Srpaulo * modification, are permitted provided that the following conditions
13176428Srpaulo * are met:
14176428Srpaulo * 1. Redistributions of source code must retain the above copyright
15176428Srpaulo *    notice, this list of conditions and the following disclaimer.
16176428Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
17176428Srpaulo *    notice, this list of conditions and the following disclaimer in the
18176428Srpaulo *    documentation and/or other materials provided with the distribution.
19176428Srpaulo *
20176428Srpaulo * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21176428Srpaulo * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22176428Srpaulo * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23176428Srpaulo * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24176428Srpaulo * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25176428Srpaulo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26176428Srpaulo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27176428Srpaulo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28176428Srpaulo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29176428Srpaulo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30176428Srpaulo * POSSIBILITY OF SUCH DAMAGE.
31176428Srpaulo */
32176428Srpaulo
33176428Srpaulo#include <sys/cdefs.h>
34176428Srpaulo#include <sys/types.h>
35176428Srpaulo#include <sys/socket.h>
36176428Srpaulo#include <netinet/in.h>
37176428Srpaulo#include <arpa/inet.h>
38176428Srpaulo#include <netdb.h>
39176428Srpaulo#include <unistd.h>
40176428Srpaulo#include <string.h>
41176428Srpaulo#include <stdlib.h>
42176428Srpaulo#include <errno.h>
43176428Srpaulo#include <err.h>
44176428Srpaulo#include <stdio.h>
45176428Srpaulo
46176428Srpaulo#include "as.h"
47176428Srpaulo
48176428Srpaulo#define DEFAULT_AS_SERVER "whois.radb.net"
49176428Srpaulo#undef AS_DEBUG_FILE
50176428Srpaulo
51176428Srpaulostruct aslookup {
52176428Srpaulo	FILE *as_f;
53176428Srpaulo#ifdef AS_DEBUG_FILE
54176428Srpaulo	FILE *as_debug;
55176428Srpaulo#endif /* AS_DEBUG_FILE */
56176428Srpaulo};
57176428Srpaulo
58176428Srpaulovoid *
59216184Suqsas_setup(const char *server)
60176428Srpaulo{
61176428Srpaulo	struct aslookup *asn;
62196475Sume	struct addrinfo hints, *res0, *res;
63176428Srpaulo	FILE *f;
64196475Sume	int s, error;
65176428Srpaulo
66216184Suqs	s = -1;
67176428Srpaulo	if (server == NULL)
68196475Sume		server = getenv("RA_SERVER");
69196475Sume	if (server == NULL)
70176428Srpaulo		server = DEFAULT_AS_SERVER;
71176428Srpaulo
72196475Sume	memset(&hints, 0, sizeof(hints));
73196475Sume	hints.ai_family = PF_UNSPEC;
74196475Sume	hints.ai_socktype = SOCK_STREAM;
75196475Sume	error = getaddrinfo(server, "whois", &hints, &res0);
76196475Sume	if (error == EAI_SERVICE) {
77176428Srpaulo		warnx("warning: whois/tcp service not found");
78196475Sume		error = getaddrinfo(server, "43", &hints, &res0);
79176428Srpaulo	}
80196475Sume	if (error != 0) {
81196475Sume		warnx("%s: %s", server, gai_strerror(error));
82176428Srpaulo		return (NULL);
83176428Srpaulo	}
84176428Srpaulo
85196475Sume	for (res = res0; res; res = res->ai_next) {
86196475Sume		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
87196475Sume		if (s < 0)
88196475Sume			continue;
89196475Sume		if (connect(s, res->ai_addr, res->ai_addrlen) >= 0)
90176428Srpaulo			break;
91196475Sume		close(s);
92196475Sume		s = -1;
93196475Sume	}
94196475Sume	freeaddrinfo(res0);
95196475Sume	if (s < 0) {
96176428Srpaulo		warn("connect");
97176428Srpaulo		return (NULL);
98176428Srpaulo	}
99176428Srpaulo
100176428Srpaulo	f = fdopen(s, "r+");
101176428Srpaulo	(void)fprintf(f, "!!\n");
102176428Srpaulo	(void)fflush(f);
103176428Srpaulo
104176428Srpaulo	asn = malloc(sizeof(struct aslookup));
105176428Srpaulo	if (asn == NULL)
106176428Srpaulo		(void)fclose(f);
107176428Srpaulo	else
108176428Srpaulo		asn->as_f = f;
109176428Srpaulo
110176428Srpaulo#ifdef AS_DEBUG_FILE
111176428Srpaulo	asn->as_debug = fopen(AS_DEBUG_FILE, "w");
112176428Srpaulo	if (asn->as_debug) {
113176428Srpaulo		(void)fprintf(asn->as_debug, ">> !!\n");
114176428Srpaulo		(void)fflush(asn->as_debug);
115176428Srpaulo	}
116176428Srpaulo#endif /* AS_DEBUG_FILE */
117176428Srpaulo
118176428Srpaulo	return (asn);
119176428Srpaulo}
120176428Srpaulo
121196475Sumeunsigned int
122196475Sumeas_lookup(void *_asn, char *addr, sa_family_t family)
123176428Srpaulo{
124176428Srpaulo	struct aslookup *asn = _asn;
125176428Srpaulo	char buf[1024];
126196475Sume	unsigned int as;
127196475Sume	int rc, dlen, plen;
128176428Srpaulo
129196475Sume	as = 0;
130196475Sume	rc = dlen = 0;
131196475Sume	plen = (family == AF_INET6) ? 128 : 32;
132196475Sume	(void)fprintf(asn->as_f, "!r%s/%d,l\n", addr, plen);
133176428Srpaulo	(void)fflush(asn->as_f);
134176428Srpaulo
135176428Srpaulo#ifdef AS_DEBUG_FILE
136176428Srpaulo	if (asn->as_debug) {
137196475Sume		(void)fprintf(asn->as_debug, ">> !r%s/%d,l\n", addr, plen);
138176428Srpaulo		(void)fflush(asn->as_debug);
139176428Srpaulo	}
140176428Srpaulo#endif /* AS_DEBUG_FILE */
141176428Srpaulo
142176428Srpaulo	while (fgets(buf, sizeof(buf), asn->as_f) != NULL) {
143176428Srpaulo		buf[sizeof(buf) - 1] = '\0';
144176428Srpaulo
145176428Srpaulo#ifdef AS_DEBUG_FILE
146176428Srpaulo		if (asn->as_debug) {
147176428Srpaulo			(void)fprintf(asn->as_debug, "<< %s", buf);
148176428Srpaulo			(void)fflush(asn->as_debug);
149176428Srpaulo		}
150176428Srpaulo#endif /* AS_DEBUG_FILE */
151176428Srpaulo
152176428Srpaulo		if (rc == 0) {
153176428Srpaulo			rc = buf[0];
154176428Srpaulo			switch (rc) {
155176428Srpaulo			    case 'A':
156176428Srpaulo				/* A - followed by # bytes of answer */
157176428Srpaulo				sscanf(buf, "A%d\n", &dlen);
158176428Srpaulo#ifdef AS_DEBUG_FILE
159176428Srpaulo				if (asn->as_debug) {
160176428Srpaulo					(void)fprintf(asn->as_debug,
161176428Srpaulo					     "dlen: %d\n", dlen);
162176428Srpaulo					(void)fflush(asn->as_debug);
163176428Srpaulo				}
164176428Srpaulo#endif /* AS_DEBUG_FILE */
165176428Srpaulo				break;
166196475Sume			    case 'C':
167176428Srpaulo			    case 'D':
168176428Srpaulo			    case 'E':
169176428Srpaulo			    case 'F':
170176428Srpaulo				/* C - no data returned */
171176428Srpaulo				/* D - key not found */
172176428Srpaulo				/* E - multiple copies of key */
173176428Srpaulo				/* F - some other error */
174176428Srpaulo				break;
175176428Srpaulo			}
176176428Srpaulo			if (rc == 'A')
177176428Srpaulo				/* skip to next input line */
178176428Srpaulo				continue;
179176428Srpaulo		}
180176428Srpaulo
181176428Srpaulo		if (dlen == 0)
182176428Srpaulo			/* out of data, next char read is end code */
183176428Srpaulo			rc = buf[0];
184176428Srpaulo		if (rc != 'A')
185176428Srpaulo			/* either an error off the bat, or a done code */
186176428Srpaulo			break;
187176428Srpaulo
188176428Srpaulo		/* data received, thank you */
189176428Srpaulo		dlen -= strlen(buf);
190176428Srpaulo
191176428Srpaulo		/* origin line is the interesting bit */
192176428Srpaulo		if (as == 0 && strncasecmp(buf, "origin:", 7) == 0) {
193196475Sume			sscanf(buf + 7, " AS%u", &as);
194176428Srpaulo#ifdef AS_DEBUG_FILE
195176428Srpaulo			if (asn->as_debug) {
196176428Srpaulo				(void)fprintf(asn->as_debug, "as: %d\n", as);
197176428Srpaulo				(void)fflush(asn->as_debug);
198176428Srpaulo			}
199176428Srpaulo#endif /* AS_DEBUG_FILE */
200176428Srpaulo		}
201176428Srpaulo	}
202176428Srpaulo
203176428Srpaulo	return (as);
204176428Srpaulo}
205176428Srpaulo
206176428Srpaulovoid
207196475Sumeas_shutdown(void *_asn)
208176428Srpaulo{
209176428Srpaulo	struct aslookup *asn = _asn;
210176428Srpaulo
211176428Srpaulo	(void)fprintf(asn->as_f, "!q\n");
212176428Srpaulo	(void)fclose(asn->as_f);
213176428Srpaulo
214176428Srpaulo#ifdef AS_DEBUG_FILE
215176428Srpaulo	if (asn->as_debug) {
216176428Srpaulo		(void)fprintf(asn->as_debug, ">> !q\n");
217176428Srpaulo		(void)fclose(asn->as_debug);
218176428Srpaulo	}
219176428Srpaulo#endif /* AS_DEBUG_FILE */
220176428Srpaulo
221176428Srpaulo	free(asn);
222176428Srpaulo}
223