summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile32
-rw-r--r--config.h2
-rw-r--r--data.h21
-rw-r--r--debian/changelog13
-rwxr-xr-xdebian/rules2
-rwxr-xr-xmake_servers_charset.pl21
-rw-r--r--servers_charset.h34
-rw-r--r--servers_charset_list37
-rw-r--r--simple_recode.c176
-rw-r--r--simple_recode.h14
-rw-r--r--tld_serv_list27
-rw-r--r--whois-4.6.6-gentoo-security.patch90
-rw-r--r--whois.135
-rw-r--r--whois.c417
-rw-r--r--whois.h9
-rw-r--r--whois.spec4
16 files changed, 623 insertions, 311 deletions
diff --git a/Makefile b/Makefile
index 61fa03c..44f09dd 100644
--- a/Makefile
+++ b/Makefile
@@ -5,10 +5,15 @@ CFLAGS = -g -O2
PERL = perl
INSTALL = install
+whois_OBJECTS := whois.o utils.o
+mkpasswd_OBJECTS := mkpasswd.o utils.o
+
+##############################################################################
# Solaris
-#whois_LDADD += -lnsl -lsocket
+#whois_LDADD += -lnsl -lsocket -liconv
# FreeBSD
+#whois_LDADD += -liconv
#LIBS += -L/usr/local/lib -lintl
#INCLUDES += -I/usr/local/include
@@ -16,6 +21,9 @@ INSTALL = install
#whois_LDADD += -lsocket
#LDFLAGS += -Zexe -Dstrncasecmp=strnicmp
+# OS X
+#whois_LDADD += -liconv
+
ifdef CONFIG_FILE
DEFS += -DCONFIG_FILE=\"$(CONFIG_FILE)\"
endif
@@ -29,6 +37,11 @@ whois_LDADD += -lidn
DEFS += -DHAVE_LIBIDN
endif
+ifdef HAVE_ICONV
+whois_OBJECTS += simple_recode.o
+DEFS += -DHAVE_ICONV
+endif
+
ifdef HAVE_XCRYPT
mkpasswd_LDADD += -lxcrypt
DEFS += -DHAVE_XCRYPT
@@ -36,11 +49,9 @@ else
mkpasswd_LDADD += -lcrypt
endif
+##############################################################################
all: Makefile.depend whois mkpasswd #pos
-whois_OBJECTS := whois.o utils.o
-mkpasswd_OBJECTS := mkpasswd.o utils.o
-
##############################################################################
%.o: %.c
$(CC) $(DEFS) $(INCLUDES) $(CFLAGS) -c $<
@@ -53,19 +64,22 @@ mkpasswd: $(mkpasswd_OBJECTS)
##############################################################################
as_del.h: as_del_list make_as_del.pl
- $(PERL) -w make_as_del.pl < as_del_list > $@
+ $(PERL) -w make_as_del.pl < $< > $@
as32_del.h: as32_del_list make_as32_del.pl
- $(PERL) -w make_as32_del.pl < as32_del_list > $@
+ $(PERL) -w make_as32_del.pl < $< > $@
ip_del.h: ip_del_list make_ip_del.pl
- $(PERL) -w make_ip_del.pl < ip_del_list > $@
+ $(PERL) -w make_ip_del.pl < $< > $@
ip6_del.h: ip6_del_list make_ip6_del.pl
- $(PERL) -w make_ip6_del.pl < ip6_del_list > $@
+ $(PERL) -w make_ip6_del.pl < $< > $@
tld_serv.h: tld_serv_list make_tld_serv.pl
- $(PERL) -w make_tld_serv.pl < tld_serv_list > $@
+ $(PERL) -w make_tld_serv.pl < $< > $@
+
+servers_charset.h: servers_charset_list make_servers_charset.pl
+ $(PERL) -w make_servers_charset.pl < $< > $@
##############################################################################
install: install-whois install-mkpasswd #install-pos
diff --git a/config.h b/config.h
index 2b88b45..7d7f415 100644
--- a/config.h
+++ b/config.h
@@ -1,5 +1,5 @@
/* Program version */
-#define VERSION "4.7.37"
+#define VERSION "5.0.0"
/* Configurable features */
diff --git a/data.h b/data.h
index e20d396..89984fa 100644
--- a/data.h
+++ b/data.h
@@ -21,8 +21,10 @@ const char *ripe_servers[] = {
"whois.arnes.si",
"www.registry.co.ug",
"whois.nic.ir",
+ "whois.pandi.or.id",
"whois.nic.ck",
"whois.ra.net",
+ "whois.bgpmon.net",
NULL
};
@@ -74,12 +76,6 @@ const char *nic_handles[] = {
"poem-", "whois.ripe.net",
"form-", "whois.ripe.net",
"pgpkey-", "whois.ripe.net",
-#if 0
- // commented until somebody will explain the query format for these
- "coco-", "whois.corenic.net",
- "coho-", "whois.corenic.net",
- "core-", "whois.corenic.net",
-#endif
"denic-", "whois.denic.de",
/* RPSL objects */
"as-", "whois.ripe.net",
@@ -139,3 +135,16 @@ const char *tld_serv[] = {
NULL, NULL
};
+#ifdef HAVE_ICONV
+struct server_charset {
+ const char *name;
+ const char *charset;
+ const char *options;
+};
+
+const struct server_charset servers_charset[] = {
+#include "servers_charset.h"
+ { NULL, NULL, NULL }
+};
+#endif
+
diff --git a/debian/changelog b/debian/changelog
index bf5fa59..c19264e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,16 @@
+whois (5.0.0) unstable; urgency=low
+
+ * Added optional support for automatically transcoding the output of
+ servers. (Closes: #363366, #402356)
+ * Automatically add --show-handles to queries for .dk domains.
+ * Normalize the querystring and convert it to punycode even if a server
+ is specified on the command line.
+ * Updated the .id, .is, .my, .sb and .tj TLD servers.
+ * Removed the .mm, .pw, .sr and .tp TLD servers.
+ * Cleaned up the horrible strings manipulation code. (Closes: #131924)
+
+ -- Marco d'Itri <md@linux.it> Sun, 20 Dec 2009 03:01:40 +0100
+
whois (4.7.37) unstable; urgency=medium
* Added new ASN allocations.
diff --git a/debian/rules b/debian/rules
index 09fceb8..558b921 100755
--- a/debian/rules
+++ b/debian/rules
@@ -9,7 +9,7 @@ VERSION := $(shell dpkg-parsechangelog | sed -n 's/\+.*$$//; /^Version/s/.* //p'
build:
dh_testdir
- $(MAKE) CONFIG_FILE="/etc/whois.conf" HAVE_LIBIDN=1
+ $(MAKE) CONFIG_FILE="/etc/whois.conf" HAVE_LIBIDN=1 HAVE_ICONV=1
cd po && $(MAKE) whois.pot
touch $@
diff --git a/make_servers_charset.pl b/make_servers_charset.pl
new file mode 100755
index 0000000..8517b75
--- /dev/null
+++ b/make_servers_charset.pl
@@ -0,0 +1,21 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+
+while (<>) {
+ chomp;
+ s/#.*$//;
+ s/^\s+//; s/\s+$//;
+ next if /^$/;
+
+ die "format error: $_" unless
+ (my ($a, $b, $c) = /^([a-z0-9.-]+)\s+([a-z0-9-]+)(?:\s+(.+))?$/);
+
+ if ($c) {
+ print qq( { "$a",\t"$b",\t"$c" },\n);
+ } else {
+ print qq( { "$a",\t"$b",\tNULL },\n);
+ }
+}
+
diff --git a/servers_charset.h b/servers_charset.h
new file mode 100644
index 0000000..d8539ee
--- /dev/null
+++ b/servers_charset.h
@@ -0,0 +1,34 @@
+ { "whois.corenic.net", "utf-8", "-C UTF-8" },
+ { "whois.cat", "utf-8", "-C UTF-8" },
+ { "whois.museum", "utf-8", "-C UTF-8" },
+ { "whois.nic.br", "iso-8859-1", NULL },
+ { "whois.cira.ca", "iso-8859-1", NULL },
+ { "whois.nic.ch", "utf-8", NULL },
+ { "whois.nic.cl", "iso-8859-1", NULL },
+ { "whois.cnnic.net.cn", "utf-8", NULL },
+ { "whois.nic.cz", "utf-8", NULL },
+ { "whois.denic.de", "utf-8", NULL },
+ { "whois.enum.denic.de", "utf-8", NULL },
+ { "whois.dk-hostmaster.dk", "utf-8", "--charset=utf-8" },
+ { "whois.eenet.ee", "iso-8859-1", NULL },
+ { "whois.eu", "utf-8", NULL },
+ { "whois.ficora.fi", "iso-8859-1", NULL },
+ { "whois.nic.fr", "iso-8859-1", NULL },
+ { "whois.hkdnr.net.hk", "utf-8", NULL },
+ { "whois.nic.hu", "iso-8859-1", NULL },
+ { "whois.isnic.is", "iso-8859-1", NULL },
+ { "whois.jprs.jp", "iso-2022-jp", NULL },
+ { "whois.nic.ad.jp", "iso-2022-jp", NULL },
+ { "whois.nic.or.kr", "euc-kr", NULL },
+ { "whois.nic.li", "utf-8", NULL },
+ { "whois.domreg.lt", "utf-8", NULL },
+ { "whois.dns.lu", "iso-8859-1", NULL },
+ { "whois.nic.mu", "utf-8", NULL },
+ { "whois.norid.no", "iso-8859-1", NULL },
+ { "whois.nic.nu", "utf-8", NULL },
+ { "whois.dns.pt", "iso-8859-1", NULL },
+ { "whois.nic-se.se", "utf-8", NULL },
+ { "whois.nic.tr", "utf-8", NULL },
+ { "whois.twnic.net", "utf-8", NULL },
+ { "whois.net.ua", "koi8-u", NULL },
+ { "whois.nic.org.uy", "utf-8", NULL },
diff --git a/servers_charset_list b/servers_charset_list
new file mode 100644
index 0000000..d2b6e77
--- /dev/null
+++ b/servers_charset_list
@@ -0,0 +1,37 @@
+# server name charset optional parameters
+whois.corenic.net utf-8 -C UTF-8
+whois.cat utf-8 -C UTF-8
+whois.museum utf-8 -C UTF-8
+
+whois.nic.br iso-8859-1
+whois.cira.ca iso-8859-1
+whois.nic.ch utf-8
+whois.nic.cl iso-8859-1
+whois.cnnic.net.cn utf-8
+whois.nic.cz utf-8
+whois.denic.de utf-8
+whois.enum.denic.de utf-8
+whois.dk-hostmaster.dk utf-8 --charset=utf-8
+whois.eenet.ee iso-8859-1
+whois.eu utf-8
+whois.ficora.fi iso-8859-1
+whois.nic.fr iso-8859-1
+whois.hkdnr.net.hk utf-8
+whois.nic.hu iso-8859-1
+whois.isnic.is iso-8859-1
+whois.jprs.jp iso-2022-jp
+whois.nic.ad.jp iso-2022-jp
+whois.nic.or.kr euc-kr
+whois.nic.li utf-8
+whois.domreg.lt utf-8
+whois.dns.lu iso-8859-1
+whois.nic.mu utf-8
+whois.norid.no iso-8859-1
+whois.nic.nu utf-8
+whois.dns.pt iso-8859-1
+whois.nic-se.se utf-8
+whois.nic.tr utf-8
+whois.twnic.net utf-8
+whois.net.ua koi8-u
+whois.nic.org.uy utf-8
+
diff --git a/simple_recode.c b/simple_recode.c
new file mode 100644
index 0000000..e7d9bb5
--- /dev/null
+++ b/simple_recode.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2009 by Marco d'Itri <md@linux.it>.
+ *
+ * simple_recode was inspired by a similar function found in Simon
+ * Josefsson's libidn.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <iconv.h>
+#include <langinfo.h>
+
+#include "utils.h"
+
+#include "simple_recode.h"
+
+/* Global variables */
+iconv_t simple_recode_iconv_handle;
+const char *simple_recode_input_charset;
+
+/*
+ * These value should be tuned to an acceptable compromise between memory
+ * usage and calling iconv(3) as few times as possible.
+ */
+#define SIMPLE_RECODE_BUFFER_SIZE_1 256
+#define SIMPLE_RECODE_BUFFER_SIZE_2 1024
+#define SIMPLE_RECODE_BUFFER_INCREMENT 1
+
+/*
+ * Convert a NULL-terminated string accordingly to the provided iconv(3)
+ * handle. The returned string is allocated using malloc(3) and needs to be
+ * deallocated by the caller.
+ * Incomplete, invalid and impossible to recode sequences are copied as-is.
+ * On failure, NULL is returned and errno is set.
+ */
+char *simple_recode(const iconv_t handle, const char *str)
+{
+ char *inp = (char *) str;
+ char *outp, *result;
+ size_t inbytes_remaining, outbytes_remaining, outbuf_size;
+
+ inbytes_remaining = strlen(inp);
+ if (inbytes_remaining + 1 <= SIMPLE_RECODE_BUFFER_SIZE_1
+ - (SIMPLE_RECODE_BUFFER_SIZE_1 >> SIMPLE_RECODE_BUFFER_INCREMENT))
+ outbuf_size = SIMPLE_RECODE_BUFFER_SIZE_1;
+ else
+ outbuf_size = inbytes_remaining + 1
+ + (inbytes_remaining >> SIMPLE_RECODE_BUFFER_INCREMENT);
+
+ outp = result = malloc(outbuf_size);
+ if (!result)
+ return NULL;
+ outbytes_remaining = outbuf_size - 1;
+
+ do {
+ size_t err = iconv(handle, &inp, &inbytes_remaining, &outp,
+ &outbytes_remaining);
+
+ if (err != -1)
+ break; /* success */
+
+ switch (errno) {
+ case EINVAL: /* incomplete multibyte sequence */
+ case EILSEQ: /* invalid multibyte sequence */
+#ifdef SIMPLE_RECODE_SKIP_INVALID_SEQUENCES
+ /* recover from invalid input by replacing it with a '?' */
+ inp++;
+ *outp++ = '?'; /* use U+FFFD for unicode output? how? */
+#else
+ /* garbage in, garbage out */
+ *outp++ = *inp++;
+#endif
+ inbytes_remaining--;
+ outbytes_remaining--;
+ continue;
+
+ case E2BIG:
+ {
+ size_t used = outp - result;
+ size_t newsize;
+
+ if (outbuf_size < SIMPLE_RECODE_BUFFER_SIZE_2)
+ newsize = SIMPLE_RECODE_BUFFER_SIZE_2;
+ else
+ newsize = outbuf_size
+ + (outbuf_size >> SIMPLE_RECODE_BUFFER_INCREMENT);
+
+ /* check if the newsize variable has overflowed */
+ if (newsize <= outbuf_size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ outbuf_size = newsize;
+ result = realloc(result, outbuf_size);
+ if (!result)
+ return NULL;
+
+ /* update the position in the new output stream */
+ outp = result + used;
+ outbytes_remaining = outbuf_size - used - 1;
+
+ continue;
+ }
+
+ default:
+ return NULL;
+ }
+ } while (inbytes_remaining > 0);
+
+ *outp = '\0';
+
+ return result;
+}
+
+/*
+ * Like fputs(3), but transparently recodes s using the global variable
+ * simple_recode_input_charset as the input charset and the current locale
+ * as the output charset.
+ * If simple_recode_input_charset is NULL it just calls fputs(3).
+ * Exits with an error if iconv(3) or iconv_open(3) fail.
+ *
+ * Assumes that setlocale(3) has already been called.
+ *
+ * If appropriate, the iconv object referenced by the global variable
+ * simple_recode_iconv_handle should be deallocated with iconv_close(3).
+ */
+int recode_fputs(const char *s, FILE *stream)
+{
+ char *out;
+ int result;
+
+ if (simple_recode_input_charset == NULL) /* no conversion is needed */
+ return fputs(s, stream);
+
+ if (simple_recode_iconv_handle == NULL) {
+ simple_recode_iconv_handle = iconv_open(nl_langinfo(CODESET),
+ simple_recode_input_charset);
+ if (simple_recode_iconv_handle == (iconv_t) - 1)
+ err_sys("iconv_open");
+ }
+
+ out = simple_recode(simple_recode_iconv_handle, s);
+ if (!out)
+ err_sys("iconv");
+ result = fputs(out, stream);
+ free(out);
+
+ return result;
+}
+
+void simple_recode_iconv_close(void)
+{
+ if (simple_recode_iconv_handle == NULL)
+ return;
+
+ iconv_close(simple_recode_iconv_handle);
+ simple_recode_iconv_handle = NULL;
+ simple_recode_input_charset = NULL;
+}
+
diff --git a/simple_recode.h b/simple_recode.h
new file mode 100644
index 0000000..5fc95b0
--- /dev/null
+++ b/simple_recode.h
@@ -0,0 +1,14 @@
+#ifndef SIMPLE_RECODE_H
+#define SIMPLE_RECODE_H
+
+#include <iconv.h>
+#include <stdio.h>
+
+extern iconv_t simple_recode_iconv_handle;
+extern const char *simple_recode_input_charset;
+
+char *simple_recode(const iconv_t handle, const char *str);
+int recode_fputs(const char *s, FILE* stream);
+void simple_recode_iconv_close(void);
+
+#endif
diff --git a/tld_serv_list b/tld_serv_list
index 81231fe..5cc6e80 100644
--- a/tld_serv_list
+++ b/tld_serv_list
@@ -80,6 +80,7 @@
.bh NONE # www.inet.com.bh
.bi WEB http://whois.nic.bi/register/whois.hei # whois.nic.bi wrong referral?
.bj whois.nic.bj
+#.bl
.bm WEB http://207.228.133.14/cgi-bin/lansaweb?procfun+BMWHO+BMWHO2+WHO
.bn NONE # www.brunet.bn
.bo WEB http://www.nic.bo/
@@ -156,7 +157,7 @@
.hr WEB http://www.dns.hr/pretrazivanje.html
.ht whois.nic.ht
.hu whois.nic.hu
-.id whois.idnic.net.id
+.id whois.pandi.or.id
.ie whois.domainregistry.ie
.il whois.isoc.org.il
.im whois.nic.im
@@ -164,7 +165,7 @@
.io whois.nic.io
.iq NONE # http://www.cmc.iq/english/iq/iqregister1.htm
.ir whois.nic.ir
-.is whois.isnet.is
+.is whois.isnic.is
.it whois.nic.it
.je whois.je
.jm NONE # NIC? uwimona.edu.jm http://nic.jm
@@ -196,11 +197,12 @@
.mc whois.ripe.net
.md WEB http://www.dns.md/wh1.php # whois.nic.md is restricted
.me whois.meregistry.net # afilias
+#.mf
.mg whois.nic.mg
.mh NONE # www.nic.net.mh
.mk WEB http://dns.marnet.net.mk/registar.php
.ml NONE # NIC? www.sotelma.ml
-.mm whois.nic.mm
+.mm NONE # NO NIC
.mn AFILIAS
.mo WEB http://www.monic.net.mo/
.mp NONE # get.mp
@@ -212,7 +214,7 @@
.mv NONE # NIC? www.dhiraagu.com.mv
.mw WEB http://www.registrar.mw/
.mx whois.nic.mx
-.my whois.mynic.net.my
+.my whois.domainregistry.my
.mz NONE # NIC? www.uem.mz
.na whois.na-nic.com.na
.nc whois.cctld.nc
@@ -240,7 +242,7 @@
.pr whois.nic.pr
.ps WEB http://www.nic.ps/whois/whois.html
.pt whois.dns.pt
-.pw whois.nic.pw
+.pw NONE # NO NIC
.py WEB http://www.nic.py/consultas.html
.qa NONE # http://www.qtel.com.qa/InternetFeatures.do
.re whois.nic.fr
@@ -250,7 +252,7 @@
.ru whois.ripn.net
.rw WEB http://www.nic.rw/cgi-bin/whoisrw.pl
.sa saudinic.net.sa
-.sb whois.nic.net.sb
+.sb whois.coccaregistry.net
.sc AFILIAS # www.nic.sc
.sd NONE # http://isoc.sd/ (CHECK LATER)
.se whois.nic-se.se
@@ -263,7 +265,7 @@
.sm whois.ripe.net
.sn whois.nic.sn
.so NONE # www.nic.so (CHECK LATER, recently delegated)
-.sr whois.register.sr
+.sr NONE # www.register.sr
.st whois.nic.st
.su whois.ripn.net
.sv WEB http://www.uca.edu.sv/dns/ # http://www.svnet.org.sv/
@@ -274,13 +276,13 @@
.tf whois.nic.tf
.tg WEB http://www.nic.tg/
.th whois.thnic.net
-.tj whois.nic.tj
+.tj WEB http://www.nic.tj/whois.html
.tk whois.dot.tk
.tl whois.nic.tl
.tm whois.nic.tm
.tn WEB http://whois.ati.tn/
.to whois.tonic.to
-.tp whois.nic.tp
+.tp NONE # phase out in progress
.tr whois.nic.tr
.tt WEB http://www.nic.tt/cgi-bin/search.pl
.tv VERISIGN whois.nic.tv
@@ -300,6 +302,7 @@
.parliament.uk NONE
.police.uk NONE
.uk whois.nic.uk
+#.um
.fed.us whois.nic.gov
.us whois.nic.us
.com.uy WEB https://nic.anteldata.com.uy/dns/
@@ -312,10 +315,10 @@
.vi WEB http://www.nic.vi/whoisform.htm
.vn WEB http://www.vnnic.vn/english/
.vu WEB http://www.vunic.vu/whois.html
-.wf whois.nic.wf
+.wf whois.nic.fr
.ws whois.samoanic.ws
.ye NONE # NIC? www.nominet.org.ye http://www.y.net.ye/services/domain_name.htm
-.yt whois.nic.yt
+.yt whois.nic.fr
.yu NONE # www.nic.yu - phase out date: 30 March 2009
.ac.za whois.ac.za
.co.za whois.coza.net.za
@@ -340,7 +343,7 @@
-cz whois.nic.cz
-dk whois.dk-hostmaster.dk
-il whois.isoc.org.il
--is whois.isnet.is
+-is whois.isnic.is
-kg whois.domain.kg
-ti whois.telstra.net
-tw whois.twnic.net
diff --git a/whois-4.6.6-gentoo-security.patch b/whois-4.6.6-gentoo-security.patch
deleted file mode 100644
index d933b91..0000000
--- a/whois-4.6.6-gentoo-security.patch
+++ /dev/null
@@ -1,90 +0,0 @@
-The gentoo people submitted this patch. I'm not applying it as it makes
-the code harder to understand with no major gain and without being a
-fully correct fix.
-
-diff -Nru whois-4.6.6.orig/whois.c whois-4.6.6/whois.c
---- whois-4.6.6.orig/whois.c 2003-06-15 12:36:52.000000000 -0400
-+++ whois-4.6.6/whois.c 2003-08-11 02:15:30.000000000 -0400
-@@ -73,12 +73,12 @@
- /* RIPE flags */
- if (strchr(ripeflags, ch)) {
- for (p = fstring; *p; p++);
-- sprintf(p--, "-%c ", ch);
-+ snprintf(p--, sizeof(fstring), "-%c ", ch);
- continue;
- }
- if (strchr(ripeflagsp, ch)) {
- for (p = fstring; *p; p++);
-- sprintf(p--, "-%c %s ", ch, optarg);
-+ snprintf(p--, sizeof(fstring), "-%c %s ", ch, optarg);
- if (ch == 't' || ch == 'v' || ch == 'q')
- nopar = 1;
- continue;
-@@ -132,10 +132,10 @@
- while (1) {
- qslen += strlen(*argv) + 1 + 1;
- qstring = realloc(qstring, qslen);
-- strcat(qstring, *argv++);
-+ strncat(qstring, *argv++, qslen-1);
- if (argc == 1)
- break;
-- strcat(qstring, " ");
-+ strncat(qstring, " ", qslen);
- argc--;
- }
- }
-@@ -401,10 +401,13 @@
- {
- char *buf;
- int i, isripe = 0;
-+ int buflen = 0;
-
- /* +10 for CORE; +2 for \r\n; +1 for NULL */
-- buf = malloc(strlen(flags) + strlen(query) + strlen(client_tag) + 4
-- + 10 + 2 + 1);
-+ buflen = (strlen(flags) + strlen(query) + strlen(client_tag) + 4 + 10 + 2 + 1);
-+
-+ buf = malloc(buflen);
-+
- *buf = '\0';
- for (i = 0; ripe_servers[i]; i++)
- if (strcmp(server, ripe_servers[i]) == 0) {
-@@ -426,23 +429,23 @@
- if (*flags) {
- if (!isripe && strcmp(server, "whois.corenic.net") != 0)
- puts(_("Warning: RIPE flags used with a traditional server."));
-- strcat(buf, flags);
-+ strncat(buf, flags, buflen);
- }
- /* FIXME: /e is not applied to .JP ASN */
- if (!isripe && (strcmp(server, "whois.nic.mil") == 0 ||
- strcmp(server, "whois.nic.ad.jp") == 0) &&
- strncasecmp(query, "AS", 2) == 0 && isasciidigit(query[2]))
-- sprintf(buf, "AS %s", query + 2); /* fix query for DDN */
-+ snprintf(buf, buflen, "AS %s", query + 2); /* fix query for DDN */
- else if (!isripe && strcmp(server, "whois.corenic.net") == 0)
-- sprintf(buf, "--machine %s", query); /* machine readable output */
-+ snprintf(buf, buflen, "--machine %s", query); /* machine readable output */
- else if (!isripe && strcmp(server, "whois.nic.ad.jp") == 0) {
- char *lang = getenv("LANG"); /* not a perfect check, but... */
- if (!lang || (strncmp(lang, "ja", 2) != 0))
-- sprintf(buf, "%s/e", query); /* ask for english text */
-+ snprintf(buf, buflen, "%s/e", query); /* ask for english text */
- else
-- strcat(buf, query);
-+ strncat(buf, query, buflen);
- } else
-- strcat(buf, query);
-+ strncat(buf, query, buflen);
- return buf;
- }
-
-@@ -485,7 +488,7 @@
-
- if (verb)
- printf(_("Detected referral to %s on %s.\n"), nq, nh);
-- strcat(nq, "\r\n");
-+ strncat(nq, "\r\n", sizeof(nq));
- fd = openconn(nh, np);
- do_query(fd, nq);
- continue;
diff --git a/whois.1 b/whois.1
index 62cb204..5607789 100644
--- a/whois.1
+++ b/whois.1
@@ -1,4 +1,4 @@
-.TH "WHOIS" "1" "4 March 2005" "Marco d'Itri" "Debian GNU/Linux"
+.TH "WHOIS" "1" "20 December 2009" "Marco d'Itri" "Debian GNU/Linux"
.SH "NAME"
whois \- client for the whois directory service
.SH "SYNOPSIS"
@@ -52,17 +52,20 @@ only search in the domains database. If you want to search for NIC handles
you have to prepend a \fI!\fP character. When you do this, the default
server becomes \fIwhois.networksolutions.com\fP.
.P
-When querying \fIwhois.nic.mil\fP for AS numbers, the program will
+When querying \fIwhois.arin.net\fP for IPv4 or IPv6 networks, the CIDR
+netmask length will be automatically removed from the query string.
+.P
+When querying \fIwhois.nic.ad.jp\fP for AS numbers, the program will
automatically convert the request in the appropriate format, inserting
a space after the string \fIAS\fP.
.P
-If the program is compiled with IDN support, when querying
-\fIwhois.denic.de\fP for domain names it will automatically add the flags
-\fI\-T dn,ace \-C US\-ASCII\fP if no flags have been specified by the user.
-The domain name will \fBalways\fP be IDN-encoded.
+When querying \fIwhois.denic.de\fP for domain names and no other
+flags have been specified, the program will automatically add the flag
+\fI\-T dn\fP.
.P
-When querying \fIwhois.corenic.net\fP, the program will automatically
-request machine-readable output.
+When querying \fIwhois.dk-hostmaster.dk\fP for domain names and no other
+flags have been specified, the program will automatically add the flag
+\fI\-\-show\-handles\fP.
.P
RIPE-specific command line options are ignored when querying non-RIPE
servers. This may or may not be the behaviour intended by the user.
@@ -75,6 +78,12 @@ to find a server before applying the normal rules. Each line of the
file should contain a regular expression to be matched against the query
text and the whois server to use, separated by white space.
.P
+The whois protocol does not specify an encoding for characters which
+cannot be represented by ASCII and implementations vary wildly.
+If the program knows that a specific server uses a certain encoding,
+if needed it will transcode the server output to the encoding specified
+by the current system locale.
+.P
Command line arguments will always be interpreted accordingly to the
current system locale and converted to the IDN ASCII Compatible Encoding.
.SH "Files"
@@ -82,8 +91,8 @@ current system locale and converted to the IDN ASCII Compatible Encoding.
.SH "ENVIRONMENT"
.IP LANG
When querying \fIwhois.nic.ad.jp\fP and \fIwhois.jprs.jp\fP english text
-is requested unless the
-\fILANG\fP environment variable specifies a Japanese locale.
+is requested unless the \fILANG\fP or \fILC_MESSAGES\fP environment
+variables specify a Japanese locale.
.IP "WHOIS_OPTIONS"
A list of options which will be evalued before the ones specified on the
command line.
@@ -101,9 +110,9 @@ the help file which can be obtained with the command:
.IP
.B whois \-h whois.ripe.net HELP
.SH "BUGS"
-The program has many buffer overflows when parsing the command line
-parameters: be sure to not pass untrusted data to it.
-It will be rewritten to use a dynamic strings library.
+The program may have buffer overflows in the command line parser:
+be sure to not pass untrusted data to it.
+It should be rewritten to use a dynamics strings library.
.SH "HISTORY"
This program closely tracks the user interface of the whois client
developed at RIPE by Ambrose Magee and others on the base of the
diff --git a/whois.c b/whois.c
index c6f36a5..0be8d30 100644
--- a/whois.c
+++ b/whois.c
@@ -40,6 +40,12 @@
#include "whois.h"
#include "utils.h"
+#ifdef HAVE_ICONV
+#include "simple_recode.h"
+#else
+#define recode_fputs(a, b) fputs(a, b)
+#endif
+
/* hack */
#define malloc(s) NOFAIL(malloc(s))
#define realloc(p, s) NOFAIL(realloc(p, s))
@@ -48,12 +54,12 @@
int sockfd, verb = 0;
#ifdef ALWAYS_HIDE_DISCL
-int hide_discl = HIDE_UNSTARTED;
+int hide_discl = HIDE_NOT_STARTED;
#else
int hide_discl = HIDE_DISABLED;
#endif
-const char *client_tag = (char *)IDSTRING;
+const char *client_tag = IDSTRING;
#ifdef HAVE_GETOPT_LONG
static const struct option longopts[] = {
@@ -72,9 +78,9 @@ extern int optind;
int main(int argc, char *argv[])
{
- int ch, nopar = 0;
+ int ch, nopar = 0, fstringlen = 64;
const char *server = NULL, *port = NULL;
- char *p, *qstring, fstring[64] = "\0";
+ char *qstring, *fstring;
#ifdef ENABLE_NLS
setlocale(LC_ALL, "");
@@ -82,6 +88,9 @@ int main(int argc, char *argv[])
textdomain(NLS_CAT_NAME);
#endif
+ fstring = malloc(fstringlen + 1);
+ *fstring = '\0';
+
/* prepend options from environment */
argv = merge_args(getenv("WHOIS_OPTIONS"), argv, &argc);
@@ -89,13 +98,20 @@ int main(int argc, char *argv[])
"abBcdFg:Gh:Hi:KlLmMp:q:rRs:St:T:v:V:x", longopts, 0)) > 0) {
/* RIPE flags */
if (strchr(ripeflags, ch)) {
- for (p = fstring; *p; p++);
- sprintf(p--, "-%c ", ch);
+ if (strlen(fstring) + 3 > fstringlen) {
+ fstringlen += 3;
+ fstring = realloc(fstring, fstringlen + 1);
+ }
+ sprintf(fstring + strlen(fstring), "-%c ", ch);
continue;
}
if (strchr(ripeflagsp, ch)) {
- for (p = fstring; *p; p++);
- snprintf(p--, sizeof(fstring), "-%c %s ", ch, optarg);
+ int flaglen = 3 + strlen(optarg) + 1;
+ if (strlen(fstring) + flaglen > fstringlen) {
+ fstringlen += flaglen;
+ fstring = realloc(fstring, fstringlen + 1);
+ }
+ sprintf(fstring + strlen(fstring), "-%c %s ", ch, optarg);
if (ch == 't' || ch == 'v' || ch == 'q')
nopar = 1;
continue;
@@ -108,7 +124,7 @@ int main(int argc, char *argv[])
case 'V':
client_tag = optarg;
case 'H':
- hide_discl = HIDE_UNSTARTED; /* enable disclaimers hiding */
+ hide_discl = HIDE_NOT_STARTED; /* enable disclaimers hiding */
break;
case 'p':
port = strdup(optarg);
@@ -131,16 +147,17 @@ int main(int argc, char *argv[])
usage();
/* On some systems realloc only works on non-NULL buffers */
+ /* I wish I could remember which ones they are... */
qstring = malloc(64);
*qstring = '\0';
/* parse other parameters, if any */
if (!nopar) {
- int qslen = 0;
+ int qstringlen = 0;
while (1) {
- qslen += strlen(*argv) + 1 + 1;
- qstring = realloc(qstring, qslen);
+ qstringlen += strlen(*argv) + 1;
+ qstring = realloc(qstring, qstringlen + 1);
strcat(qstring, *argv++);
if (argc == 1)
break;
@@ -154,12 +171,18 @@ int main(int argc, char *argv[])
signal(SIGALRM, alarm_handler);
if (getenv("WHOIS_HIDE"))
- hide_discl = HIDE_UNSTARTED;
+ hide_discl = HIDE_NOT_STARTED;
/* -v or -t has been used */
if (!server && !*qstring)
server = strdup("whois.ripe.net");
+ if (*qstring) {
+ char *tmp = normalize_domain(qstring);
+ free(qstring);
+ qstring = tmp;
+ }
+
#ifdef CONFIG_FILE
if (!server) {
server = match_config_file(qstring);
@@ -168,29 +191,24 @@ int main(int argc, char *argv[])
}
#endif
- if (!server) {
- char *tmp;
-
- tmp = normalize_domain(qstring);
- free(qstring);
- qstring = tmp;
- server = whichwhois(qstring);
- }
+ if (!server)
+ server = guess_server(qstring);
handle_query(server, port, qstring, fstring);
exit(0);
}
-/* server may be a server name from the command line, a server name got
- * from whichwhois or an encoded command/message from whichwhois.
- * server and port are allocated with malloc.
+/*
+ * Server may be a server name from the command line, a server name got
+ * from guess_server or an encoded command/message from guess_server.
+ * This function has multiple memory leaks.
*/
-const char *handle_query(const char *hserver, const char *hport,
- const char *qstring, const char *fstring)
+void handle_query(const char *hserver, const char *hport,
+ const char *query, const char *flags)
{
const char *server = NULL, *port = NULL;
- char *p;
+ char *p, *query_string;
if (hport) {
server = strdup(hserver);
@@ -200,6 +218,7 @@ const char *handle_query(const char *hserver, const char *hport,
else
split_server_port(hserver, &server, &port);
+ retry:
switch (server[0]) {
case 0:
if (!(server = getenv("WHOIS_SERVER")))
@@ -209,78 +228,77 @@ const char *handle_query(const char *hserver, const char *hport,
puts(_("This TLD has no whois server, but you can access the "
"whois database at"));
puts(server + 1);
- return NULL;
+ return;
case 3:
puts(_("This TLD has no whois server."));
- return NULL;
+ return;
case 5:
puts(_("No whois server is known for this kind of object."));
- return NULL;
+ return;
case 6:
puts(_("Unknown AS number or IP network. Please upgrade this program."));
- return NULL;
+ return;
case 4:
if (verb)
printf(_("Using server %s.\n"), server + 1);
sockfd = openconn(server + 1, NULL);
- server = query_crsnic(sockfd, qstring);
+ server = query_crsnic(sockfd, query);
break;
case 7:
if (verb)
printf(_("Using server %s.\n"),
"whois.publicinterestregistry.net");
sockfd = openconn("whois.publicinterestregistry.net", NULL);
- server = query_pir(sockfd, qstring);
+ server = query_pir(sockfd, query);
break;
case 8:
if (verb)
printf(_("Using server %s.\n"), "whois.afilias-grs.info");
sockfd = openconn("whois.afilias-grs.info", NULL);
- server = query_afilias(sockfd, qstring);
+ server = query_afilias(sockfd, query);
break;
case 0x0A:
- p = convert_6to4(qstring);
- /* XXX should fail if p = 0.0.0.0 */
+ p = convert_6to4(query);
printf(_("\nQuerying for the IPv4 endpoint %s of a 6to4 IPv6 address.\n\n"), p);
- server = whichwhois(p);
- /* XXX should fail if server[0] < ' ' */
- qstring = p; /* XXX leak */
- break;
+ server = guess_server(p);
+ query = p;
+ goto retry;
case 0x0B:
- p = convert_teredo(qstring);
+ p = convert_teredo(query);
printf(_("\nQuerying for the IPv4 endpoint %s of a Teredo IPv6 address.\n\n"), p);
- server = whichwhois(p);
- qstring = p ;
- break;
+ server = guess_server(p);
+ query = p;
+ goto retry;
case 0x0C:
- p = convert_inaddr(qstring);
- server = whichwhois(p);
- break;
+ p = convert_inaddr(query);
+ server = guess_server(p);
+ free(p);
+ goto retry;
default:
break;
}
if (!server)
- return NULL;
+ return;
- p = queryformat(server, fstring, qstring);
+ query_string = queryformat(server, flags, query);
if (verb) {
printf(_("Using server %s.\n"), server);
- printf(_("Query string: \"%s\"\n\n"), p);
+ printf(_("Query string: \"%s\"\n\n"), query_string);
}
sockfd = openconn(server, port);
- strcat(p, "\r\n");
- server = do_query(sockfd, p);
+ server = do_query(sockfd, query_string);
+ free(query_string);
/* recursion is fun */
if (server) {
printf(_("\n\nFound a referral to %s.\n\n"), server);
- handle_query(server, NULL, qstring, fstring);
+ handle_query(server, NULL, query, flags);
}
- return NULL;
+ return;
}
#ifdef CONFIG_FILE
@@ -304,9 +322,8 @@ const char *match_config_file(const char *s)
regex_t re;
#endif
- for (p = buf; *p; p++)
- if (*p == '\n')
- *p = '\0';
+ if ((p = strpbrk(buf, "\r\n")))
+ *p = '\0';
p = buf;
while (*p == ' ' || *p == '\t') /* eat leading blanks */
@@ -359,7 +376,7 @@ const char *match_config_file(const char *s)
/* Parses an user-supplied string and tries to guess the right whois server.
* Returns a statically allocated buffer.
*/
-const char *whichwhois(const char *s)
+const char *guess_server(const char *s)
{
unsigned long ip, as32;
unsigned int i;
@@ -463,6 +480,11 @@ const char *whereas(const unsigned long asn)
return "\x06";
}
+/*
+ * Construct the query string.
+ * Determines the server character set as a side effect.
+ * Returns a malloc'ed string which needs to be freed by the caller.
+ */
char *queryformat(const char *server, const char *flags, const char *query)
{
char *buf, *p;
@@ -471,59 +493,75 @@ char *queryformat(const char *server, const char *flags, const char *query)
/* 64 bytes reserved for server-specific flags added later */
buf = malloc(strlen(flags) + strlen(query) + strlen(client_tag) + 64);
*buf = '\0';
+
for (i = 0; ripe_servers[i]; i++)
if (streq(server, ripe_servers[i])) {
- strcat(buf, "-V ");
- strcat(buf, client_tag);
- strcat(buf, " ");
+ sprintf(buf + strlen(buf), "-V %s ", client_tag);
isripe = 1;
break;
}
+
if (*flags) {
- if (!isripe && !streq(server, "whois.corenic.net"))
+ if (!isripe)
puts(_("Warning: RIPE flags used with a traditional server."));
strcat(buf, flags);
}
+#ifdef HAVE_ICONV
+ simple_recode_iconv_close();
+ for (i = 0; servers_charset[i].name; i++)
+ if (streq(server, servers_charset[i].name)) {
+ simple_recode_input_charset = servers_charset[i].charset;
+ if (servers_charset[i].options) {
+ strcat(buf, servers_charset[i].options);
+ strcat(buf, " ");
+ }
+ break;
+ }
+#endif
+
#ifdef HAVE_LIBIDN
- /* why, oh why DENIC had to make whois "user friendly"?
- * Do this only if the user did not use any flag.
- */
- if (streq(server, "whois.denic.de") && domcmp(query, ".de")
- && !strchr(query, ' ') && !*flags)
- sprintf(buf, "-T dn,ace -C US-ASCII %s", query);
- else
- /* here we have another registrar who could not make things simple
- * -C sets the language for both input and output
- */
- if (!isripe && streq(server, "whois.cat") && domcmp(query, ".cat")
- && !strchr(query, ' '))
- sprintf(buf, "-C US-ASCII ace %s", query);
- else
+# define DENIC_PARAM_ACE ",ace"
+#else
+# define DENIC_PARAM_ACE ""
#endif
- if (!isripe && (streq(server, "whois.nic.mil") ||
- streq(server, "whois.nic.ad.jp")) &&
- strncaseeq(query, "AS", 2) && isasciidigit(query[2]))
- /* FIXME: /e is not applied to .JP ASN */
- sprintf(buf, "AS %s", query + 2); /* fix query for DDN */
- else if (!isripe && (streq(server, "whois.nic.ad.jp") ||
- streq(server, "whois.jprs.jp"))) {
- char *lang = getenv("LANG"); /* not a perfect check, but... */
- if (!lang || !strneq(lang, "ja", 2))
- sprintf(buf, "%s/e", query); /* ask for english text */
- else
- strcat(buf, query);
- } else if (!isripe && streq(server, "whois.arin.net") &&
- (p = strrchr(query, '/'))) {
- strncat(buf, query, p - query); /* strip CIDR */
- } else
+#ifdef HAVE_ICONV
+# define DENIC_PARAM_CHARSET ""
+#else
+# define DENIC_PARAM_CHARSET " -C US-ASCII"
+#endif
+
+ /* add useful default flags if there are no flags or multiple arguments */
+ if (isripe) { }
+ else if (strchr(query, ' ') || *flags) { }
+ else if (streq(server, "whois.denic.de") && domcmp(query, ".de"))
+ strcat(buf, "-T dn" DENIC_PARAM_ACE DENIC_PARAM_CHARSET " ");
+ else if (streq(server, "whois.dk-hostmaster.dk") && domcmp(query, ".dk"))
+ strcat(buf, "--show-handles ");
+
+ /* mangle and add the query string */
+ if (!isripe && streq(server, "whois.nic.ad.jp") &&
+ strncaseeq(query, "AS", 2) && isasciidigit(query[2])) {
+ strcat(buf, "AS ");
+ strcat(buf, query + 2);
+ }
+ else if (!isripe && streq(server, "whois.arin.net") &&
+ (p = strrchr(query, '/')))
+ strncat(buf, query, p - query); /* strip the mask length */
+ else
strcat(buf, query);
+
+ /* ask for english text */
+ if (!isripe && (streq(server, "whois.nic.ad.jp") ||
+ streq(server, "whois.jprs.jp")) && japanese_locale())
+ strcat(buf, "/e");
+
return buf;
}
/* the first parameter contains the state of this simple state machine:
* HIDE_DISABLED: hidden text finished
- * HIDE_UNSTARTED: hidden text not seen yet
+ * HIDE_NOT_STARTED: hidden text not seen yet
* >= 0: currently hiding message hide_strings[*hiding]
*/
int hide_line(int *hiding, const char *const line)
@@ -532,7 +570,7 @@ int hide_line(int *hiding, const char *const line)
if (*hiding == HIDE_DISABLED) {
return 0;
- } else if (*hiding == HIDE_UNSTARTED) { /* looking for smtng to hide */
+ } else if (*hiding == HIDE_NOT_STARTED) { /* looking for smtng to hide */
for (i = 0; hide_strings[i] != NULL; i += 2) {
if (strneq(line, hide_strings[i], strlen(hide_strings[i]))) {
*hiding = i; /* start hiding */
@@ -540,7 +578,7 @@ int hide_line(int *hiding, const char *const line)
}
}
return 0; /* don't hide this line */
- } else if (*hiding > HIDE_UNSTARTED) { /* hiding something */
+ } else if (*hiding > HIDE_NOT_STARTED) { /* hiding something */
if (*hide_strings[*hiding + 1] == '\0') { /*look for a blank line?*/
if (*line == '\n' || *line == '\r' || *line == '\0') {
*hiding = HIDE_DISABLED; /* stop hiding */
@@ -561,18 +599,19 @@ int hide_line(int *hiding, const char *const line)
/* returns a string which should be freed by the caller, or NULL */
const char *do_query(const int sock, const char *query)
{
- char buf[2000], *p;
+ char *temp, *p, buf[2000];
FILE *fi;
int hide = hide_discl;
char *referral_server = NULL;
+ temp = malloc(strlen(query) + 2 + 1);
+ strcpy(temp, query);
+ strcat(temp, "\r\n");
+
fi = fdopen(sock, "r");
- if (write(sock, query, strlen(query)) < 0)
+ if (write(sock, temp, strlen(temp)) < 0)
err_sys("write");
-/* Using shutdown used to break the buggy RIPE server. Would this work now?
- if (shutdown(sock, 1) < 0)
- err_sys("shutdown");
-*/
+ free(temp);
while (fgets(buf, sizeof(buf), fi)) {
/* 6bone-style referral:
@@ -583,7 +622,7 @@ const char *do_query(const int sock, const char *query)
if (sscanf(buf, REFERTO_FORMAT, nh, np, nq) == 3) {
/* XXX we are ignoring the new query string */
- referral_server = malloc(300);
+ referral_server = malloc(strlen(nh) + 1 + strlen(np) + 1);
sprintf(referral_server, "%s:%s", nh, np);
}
}
@@ -593,32 +632,28 @@ const char *do_query(const int sock, const char *query)
* ReferralServer: whois://whois.ripe.net
*/
if (!referral_server && strneq(buf, "ReferralServer:", 15)) {
- char *q;
-
- q = strstr(buf, "rwhois://");
- if ((q = strstr(buf, "rwhois://")))
- referral_server = strdup(q + 9);
- else if ((q = strstr(buf, "whois://")))
- referral_server = strdup(q + 8);
- if (referral_server) {
- if ((q = strchr(referral_server, '/'))
- || (q = strchr(referral_server, '\n')))
- *q = '\0';
- }
+ if ((p = strstr(buf, "rwhois://")))
+ referral_server = strdup(p + 9);
+ else if ((p = strstr(buf, "whois://")))
+ referral_server = strdup(p + 8);
+ if (referral_server && (p = strpbrk(referral_server, "/\r\n")))
+ *p = '\0';
}
if (hide_line(&hide, buf))
continue;
- for (p = buf; *p && *p != '\r' && *p != '\n'; p++);
- *p = '\0';
- fprintf(stdout, "%s\n", buf);
+ if ((p = strpbrk(buf, "\r\n")))
+ *p = '\0';
+ recode_fputs(buf, stdout);
+ fputc('\n', stdout);
}
+
if (ferror(fi))
err_sys("fgets");
fclose(fi);
- if (hide > HIDE_UNSTARTED)
+ if (hide > HIDE_NOT_STARTED)
err_quit(_("Catastrophic error: disclaimer text has been changed.\n"
"Please upgrade this program.\n"));
@@ -627,9 +662,10 @@ const char *do_query(const int sock, const char *query)
const char *query_crsnic(const int sock, const char *query)
{
- char *temp, buf[2000], *ret = NULL;
+ char *temp, *p, buf[2000];
FILE *fi;
int hide = hide_discl;
+ char *referral_server = NULL;
int state = 0;
temp = malloc(strlen(query) + 1 + 2 + 1);
@@ -640,39 +676,46 @@ const char *query_crsnic(const int sock, const char *query)
fi = fdopen(sock, "r");
if (write(sock, temp, strlen(temp)) < 0)
err_sys("write");
+ free(temp);
+
while (fgets(buf, sizeof(buf), fi)) {
/* If there are multiple matches only the server of the first record
is queried */
if (state == 0 && strneq(buf, " Domain Name:", 15))
state = 1;
if (state == 1 && strneq(buf, " Whois Server:", 16)) {
- char *p, *q;
-
for (p = buf; *p != ':'; p++); /* skip until colon */
for (p++; *p == ' '; p++); /* skip colon and spaces */
- ret = malloc(strlen(p) + 1);
- for (q = ret; *p != '\n' && *p != '\r' && *p != ' '; *q++ = *p++)
- ; /*copy data*/
- *q = '\0';
+ referral_server = strdup(p);
+ if ((p = strpbrk(referral_server, "\r\n ")))
+ *p = '\0';
state = 2;
}
+
/* the output must not be hidden or no data will be shown for
host records and not-existing domains */
- if (!hide_line(&hide, buf))
- fputs(buf, stdout);
+ if (hide_line(&hide, buf))
+ continue;
+
+ if ((p = strpbrk(buf, "\r\n")))
+ *p = '\0';
+ recode_fputs(buf, stdout);
+ fputc('\n', stdout);
}
+
if (ferror(fi))
err_sys("fgets");
+ fclose(fi);
- free(temp);
- return ret;
+ return referral_server;
}
const char *query_pir(const int sock, const char *query)
{
- char *temp, buf[2000], *ret = NULL;
+ char *temp, *p, buf[2000];
FILE *fi;
int hide = hide_discl;
+ char *referral_server = NULL;
int state = 0;
temp = malloc(strlen(query) + 5 + 2 + 1);
@@ -683,6 +726,8 @@ const char *query_pir(const int sock, const char *query)
fi = fdopen(sock, "r");
if (write(sock, temp, strlen(temp)) < 0)
err_sys("write");
+ free(temp);
+
while (fgets(buf, sizeof(buf), fi)) {
/* If there are multiple matches only the server of the first record
is queried */
@@ -691,31 +736,37 @@ const char *query_pir(const int sock, const char *query)
state = 1;
if (state == 1 &&
strneq(buf, "Registrant Street1:Whois Server:", 32)) {
- char *p, *q;
-
for (p = buf; *p != ':'; p++); /* skip until colon */
for (p++; *p != ':'; p++); /* skip until 2nd colon */
for (p++; *p == ' '; p++); /* skip colon and spaces */
- ret = malloc(strlen(p) + 1);
- for (q = ret; *p != '\n' && *p != '\r'; *q++ = *p++); /*copy data*/
- *q = '\0';
+ referral_server = strdup(p);
+ if ((p = strpbrk(referral_server, "\r\n")))
+ *p = '\0';
state = 2;
}
- if (!hide_line(&hide, buf))
- fputs(buf, stdout);
+
+ if (hide_line(&hide, buf))
+ continue;
+
+ if ((p = strpbrk(buf, "\r\n")))
+ *p = '\0';
+ recode_fputs(buf, stdout);
+ fputc('\n', stdout);
}
+
if (ferror(fi))
err_sys("fgets");
+ fclose(fi);
- free(temp);
- return ret;
+ return referral_server;
}
const char *query_afilias(const int sock, const char *query)
{
- char *temp, buf[2000], *ret = NULL;
+ char *temp, *p, buf[2000];
FILE *fi;
int hide = hide_discl;
+ char *referral_server = NULL;
int state = 0;
temp = malloc(strlen(query) + 2 + 1);
@@ -725,39 +776,37 @@ const char *query_afilias(const int sock, const char *query)
fi = fdopen(sock, "r");
if (write(sock, temp, strlen(temp)) < 0)
err_sys("write");
+ free(temp);
while (fgets(buf, sizeof(buf), fi)) {
if (state == 0 && strneq(buf, "Domain Name:", 12))
state = 1;
if (state == 1 && strneq(buf, "Whois Server:", 13)) {
- char *p, *q;
-
for (p = buf; *p != ':'; p++); /* skip until colon */
for (p++; *p == ' '; p++); /* skip colon and spaces */
- ret = malloc(strlen(p) + 1);
- for (q = ret; *p != '\n' && *p != '\r' && *p != ' '; *q++ = *p++)
- ; /*copy data*/
- *q = '\0';
+ referral_server = strdup(p);
+ if ((p = strpbrk(referral_server, "\r\n ")))
+ *p = '\0';
}
- if (!hide_line(&hide, buf)) {
- char *p;
+ if (hide_line(&hide, buf))
+ continue;
- for (p = buf; *p && *p != '\r' && *p != '\n'; p++)
- ;
+ if ((p = strpbrk(buf, "\r\n")))
*p = '\0';
- fprintf(stdout, "%s\n", buf);
- }
+ recode_fputs(buf, stdout);
+ fputc('\n', stdout);
}
+
if (ferror(fi))
err_sys("fgets");
fclose(fi);
- if (hide > HIDE_UNSTARTED)
+ if (hide > HIDE_NOT_STARTED)
err_quit(_("Catastrophic error: disclaimer text has been changed.\n"
"Please upgrade this program.\n"));
- return ret;
+ return referral_server;
}
int openconn(const char *server, const char *port)
@@ -831,9 +880,9 @@ int connect_with_timeout(int fd, const struct sockaddr *addr,
socklen_t addrlen, int timeout)
{
int savedflags, rc, connect_errno, opt;
+ unsigned int len;
fd_set fd_w;
struct timeval tv;
- size_t len;
if (timeout <= 0)
return (connect(fd, addr, addrlen));
@@ -881,7 +930,7 @@ int connect_with_timeout(int fd, const struct sockaddr *addr,
/* and report them */
if (opt != 0) {
- errno = (int) &opt;
+ errno = opt;
return -1;
}
@@ -900,6 +949,22 @@ void sighandler(int signum)
err_quit(_("Interrupted by signal %d..."), signum);
}
+int japanese_locale(void) {
+ char *lang;
+
+ lang = getenv("LC_MESSAGE");
+ if (lang) {
+ if (strneq(lang, "ja", 2))
+ return 0;
+ return 1;
+ }
+
+ lang = getenv("LANG");
+ if (lang && strneq(lang, "ja", 2))
+ return 0;
+ return 1;
+}
+
/* check if dom ends with tld */
int domcmp(const char *dom, const char *tld)
{
@@ -915,14 +980,20 @@ int domcmp(const char *dom, const char *tld)
return 0;
}
+/*
+ * Attempt to normalize a query by removing trailing dots and whitespace,
+ * then convert the domain to punycode.
+ * The function assumes that the domain is the last token of they query.
+ * Returns a malloc'ed string which needs to be freed by the caller.
+ */
char *normalize_domain(const char *dom)
{
char *p, *ret;
char *domain_start = NULL;
ret = strdup(dom);
- for (p = ret; *p; p++); p--; /* move to the last char */
/* eat trailing dots and blanks */
+ p = ret + strlen(ret);
for (; *p == '.' || *p == ' ' || *p == '\t' || p == ret; p--)
*p = '\0';
@@ -1004,61 +1075,61 @@ void split_server_port(const char *const input,
char *convert_6to4(const char *s)
{
- char *new = malloc(sizeof("255.255.255.255"));
+ char *new;
unsigned int a, b;
if (sscanf(s, "2002:%x:%x:", &a, &b) != 2)
- return (char *) "0.0.0.0";
+ return strdup("0.0.0.0");
+ new = malloc(sizeof("255.255.255.255"));
sprintf(new, "%d.%d.%d.%d", a >> 8, a & 0xff, b >> 8, b & 0xff);
return new;
}
char *convert_teredo(const char *s)
{
- char *new = malloc(sizeof("255.255.255.255"));
+ char *new;
unsigned int a, b;
if (sscanf(s, "2001:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%x:%x", &a, &b) != 2)
- return (char *) "0.0.0.0";
+ return strdup("0.0.0.0");
a ^= 0xffff;
b ^= 0xffff;
+ new = malloc(sizeof("255.255.255.255"));
sprintf(new, "%d.%d.%d.%d", a >> 8, a & 0xff, b >> 8, b & 0xff);
return new;
}
char *convert_inaddr(const char *s)
{
- char *new = malloc(sizeof("255.255.255.255"));
+ char *new;
char *endptr;
- unsigned int a, b, c;
+ unsigned int a, b = 0, c = 0;
errno = 0;
a = strtol(s, &endptr, 10);
if (errno || a < 0 || a > 255 || *endptr != '.')
- return (char *) "0.0.0.0";
+ return strdup("0.0.0.0");
if (domcmp(endptr + 1, ".in-addr.arpa")) {
b = strtol(endptr + 1, &endptr, 10); /* 1.2. */
if (errno || b < 0 || b > 255 || *endptr != '.')
- return (char *) "0.0.0.0";
+ return strdup("0.0.0.0");
if (domcmp(endptr + 1, ".in-addr.arpa")) {
c = strtol(endptr + 1, &endptr, 10); /* 1.2.3. */
if (errno || c < 0 || c > 255 || *endptr != '.')
- return (char *) "0.0.0.0";
+ return strdup("0.0.0.0");
if (domcmp(endptr + 1, ".in-addr.arpa"))
- return (char *) "0.0.0.0";
-
- sprintf(new, "%d.%d.%d.0", c, b, a);
- } else
- sprintf(new, "%d.%d.0.0", b, a);
- } else
- sprintf(new, "%d.0.0.0", a);
+ return strdup("0.0.0.0");
+ }
+ }
+ new = malloc(sizeof("255.255.255.255"));
+ sprintf(new, "%d.%d.%d.0", c, b, a);
return new;
}
diff --git a/whois.h b/whois.h
index ccd87e7..e274138 100644
--- a/whois.h
+++ b/whois.h
@@ -3,13 +3,13 @@
/* String sent to RIPE servers - MUST NOT BE LONGER THAN FIVE CHARACTERS! */
/* Do *NOT* change it if you don't know what you are doing! */
-#define IDSTRING "Md4.7"
+#define IDSTRING "Md5.0"
#define HIDE_DISABLED -2
-#define HIDE_UNSTARTED -1
+#define HIDE_NOT_STARTED -1
/* prototypes */
-const char *whichwhois(const char *);
+const char *guess_server(const char *);
const char *match_config_file(const char *);
const char *whereas(const unsigned long);
const char *whereas32(const unsigned long);
@@ -24,6 +24,7 @@ int connect_with_timeout(int, const struct sockaddr *, socklen_t, int);
void usage(void);
void alarm_handler(int);
void sighandler(int);
+int japanese_locale(void);
unsigned long myinet_aton(const char *);
unsigned long asn32_to_long(const char *);
int isasciidigit(const char);
@@ -33,7 +34,7 @@ char *normalize_domain(const char *);
char *convert_6to4(const char *);
char *convert_teredo(const char *);
char *convert_inaddr(const char *);
-const char *handle_query(const char *server, const char *port,
+void handle_query(const char *server, const char *port,
const char *qstring, const char *fstring);
void split_server_port(const char *const input, const char **server,
const char **port);
diff --git a/whois.spec b/whois.spec
index b8c7e29..0179366 100644
--- a/whois.spec
+++ b/whois.spec
@@ -1,6 +1,6 @@
Summary: Enhanced WHOIS client
Name: whois
-Version: 4.7.37
+Version: 5.0.0
Release: 1
License: GPL
Vendor: Marco d'Itri <md@linux.it>
@@ -20,7 +20,7 @@ server for most queries.
%setup
%build
-make OPTS="$RPM_OPT_FLAGS"
+make CFLAGS="$RPM_OPT_FLAGS" HAVE_LIBIDN=1 HAVE_ICONV=1
%install
rm -rf ${RPM_BUILD_ROOT}