On Fri, Sep 19, 2014 at 08:00:43PM +0300, أحمد المحمودي wrote: > Anyways, I made better patch for dico client. > > Also, I've patched dicod server to listen on IPv6 addresses, what's > left is adding IPv6 support to the ACL. ---end quoted text---
Forgot to attach patches in previous email ! -- أحمد المحمودي (Ahmed El-Mahmoudy) Digital design engineer GPG KeyID: 0xEDDDA1B7 GPG Fingerprint: 8206 A196 2084 7E6D 0DF8 B176 BC19 6A94 EDDD A1B7
diff --git a/dico/cmdline.opt b/dico/cmdline.opt
index 3bd2cb3..8d4eb20 100644
--- a/dico/cmdline.opt
+++ b/dico/cmdline.opt
@@ -51,7 +51,7 @@ END
OPTION(source,,ADDR,
[<Set a source address for TCP connections.>])
BEGIN
- source_addr = get_ipaddr(optarg);
+ source_addr = optarg;
if (source_addr == 0)
dico_die(1, 0, L_ERR, _("%s: Invalid IP or unknown host name"),
optarg);
diff --git a/dico/connect.c b/dico/connect.c
index 738b28f..dfcdfb1 100644
--- a/dico/connect.c
+++ b/dico/connect.c
@@ -272,44 +272,57 @@ dict_transcript(struct dict_connection *conn, int state)
int
dict_connect(struct dict_connection **pconn, dico_url_t url)
{
- struct sockaddr_in s;
+ struct addrinfo hints, *s;
+ char urlport[6];
int fd;
- IPADDR ip;
dico_stream_t str;
struct dict_connection *conn;
XDICO_DEBUG_F2(1, _("Connecting to %s:%d\n"), url->host,
url->port ? url->port : DICO_DICT_PORT);
- fd = socket(PF_INET, SOCK_STREAM, 0);
- if (fd == -1) {
- dico_log(L_ERR, errno,
- _("cannot create dict socket"));
- return 1;
- }
- s.sin_family = AF_INET;
- s.sin_addr.s_addr = htonl(source_addr);
- s.sin_port = 0;
- if (bind(fd, (struct sockaddr*) &s, sizeof(s)) < 0) {
- dico_log(L_ERR, errno,
- _("cannot bind AUTH socket"));
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever, TODO: user configurable?
+ hints.ai_socktype = SOCK_STREAM;
+
+ if(source_addr != NULL) {
+ getaddrinfo(source_addr, "0", &hints, &s);
+ fd = socket(s->ai_family, s->ai_socktype, s->ai_protocol);
+ if (fd == -1) {
+ dico_log(L_ERR, errno,
+ _("cannot create dict socket"));
+ return 1;
+ }
+ if (bind(fd, s->ai_addr, s->ai_addrlen) < 0) {
+ dico_log(L_ERR, errno,
+ _("cannot bind AUTH socket"));
+ }
+ freeaddrinfo(s);
}
- ip = get_ipaddr(url->host);
- if (ip == 0) {
+ sprintf(urlport, "%d", (url->port ? url->port : DICO_DICT_PORT));
+
+ if (getaddrinfo(url->host, urlport, &hints, &s) != 0) {
dico_log(L_ERR, 0, _("%s: Invalid IP or unknown host name"),
url->host);
return 1;
}
- s.sin_addr.s_addr = htonl(ip);
- s.sin_port = htons(url->port ? url->port : DICO_DICT_PORT);
- if (connect(fd, (struct sockaddr*) &s, sizeof(s)) == -1) {
+ if(source_addr == NULL) {
+ fd = socket(s->ai_family, s->ai_socktype, s->ai_protocol);
+ if (fd == -1) {
+ dico_log(L_ERR, errno,
+ _("cannot create dict socket"));
+ return 1;
+ }
+ }
+ if (connect(fd, s->ai_addr, s->ai_addrlen) == -1) {
dico_log(L_ERR, errno,
_("cannot connect to DICT server %s:%d"),
url->host, url->port ? url->port : DICO_DICT_PORT);
close(fd);
return 1;
}
+ freeaddrinfo(s);
if ((str = dico_fd_io_stream_create(fd, fd)) == NULL) {
dico_log(L_ERR, errno,
diff --git a/dico/dico-priv.h b/dico/dico-priv.h
index 046ad3f..8c711aa 100644
--- a/dico/dico-priv.h
+++ b/dico/dico-priv.h
@@ -140,7 +140,7 @@ extern struct auth_cred default_cred;
extern char *client;
extern enum dico_client_mode mode;
extern int transcript;
-extern IPADDR source_addr;
+extern char *source_addr;
extern int noauth_option;
extern unsigned levenshtein_threshold;
extern char *autologin_file;
diff --git a/dico/dico.c b/dico/dico.c
index 86491ce..4e9fd77 100644
--- a/dico/dico.c
+++ b/dico/dico.c
@@ -21,7 +21,7 @@ struct auth_cred default_cred;
char *client = DICO_CLIENT_ID;
enum dico_client_mode mode = mode_define;
int transcript;
-IPADDR source_addr = INADDR_ANY;
+char *source_addr = NULL;
int noauth_option;
unsigned levenshtein_threshold;
char *autologin_file;
diff --git a/dicod/accesslog.c b/dicod/accesslog.c
index 09991a0..4bd2af5 100644
--- a/dicod/accesslog.c
+++ b/dicod/accesslog.c
@@ -18,6 +18,10 @@
#include <fprintftime.h>
#include <xgethostname.h>
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+
static char status[2][4];
void
@@ -130,60 +134,19 @@ alog_print(FILE *fp, struct alog_instr *instr, int argc, char **argv)
static char *
sockaddr_to_hostname(struct sockaddr *sa, int resolve)
{
- struct sockaddr_in *s_in;
- char *ret;
+ char ret[NI_MAXHOST];
- switch (sa->sa_family) {
- case AF_INET:
- s_in = (struct sockaddr_in*)sa;
- if (resolve) {
- struct hostent *hp;
- hp = gethostbyaddr((char*) &s_in->sin_addr,
- sizeof(s_in->sin_addr),
- AF_INET);
- if (hp)
- return xstrdup(hp->h_name);
- }
- ret = xstrdup(inet_ntoa(s_in->sin_addr));
- break;
-
- case AF_UNIX:
- ret = xstrdup("localhost");
- break;
-
- default:
- ret = xstrdup("{unsupported family}");
- }
-
+ getnameinfo(sa, sizeof(*sa), ret, NI_MAXHOST, NULL, 0, (resolve ? 0: NI_NUMERICHOST)) ;
return ret;
}
static char *
sockaddr_to_portname(struct sockaddr *sa, int salen)
{
- struct sockaddr_in *s_in;
- struct sockaddr_un *s_un;
char buf[UINTMAX_STRSIZE_BOUND];
- char *ret;
- switch (sa->sa_family) {
- case AF_UNIX:
- s_un = (struct sockaddr_un*)sa;
- if (_S_UN_NAME(s_un, salen)[0] == 0)
- ret = xstrdup("{AF_UNIX}");
- else
- ret = xstrdup(s_un->sun_path);
- break;
-
- case AF_INET:
- s_in = (struct sockaddr_in*)sa;
- ret = xstrdup(umaxtostr(ntohs(s_in->sin_port), buf));
- break;
-
- default:
- ret = xstrdup("{unsupported family}");
- }
- return ret;
+ getnameinfo(sa, sizeof(*sa), NULL, 0, buf, UINTMAX_STRSIZE_BOUND, NI_NUMERICSERV) ;
+ return buf;
}
static void
diff --git a/dicod/dicod.c b/dicod/dicod.c
index fa4c323..bd03646 100644
--- a/dicod/dicod.c
+++ b/dicod/dicod.c
@@ -336,9 +336,9 @@ dicod_loop(dico_stream_t str)
}
replace_io_stream(str);
- if (identity_check && server_addr.sa_family == AF_INET)
- identity_name = query_ident_name((struct sockaddr_in *)&server_addr,
- (struct sockaddr_in *)&client_addr);
+ if (identity_check && ((server_addr.sa_family == AF_INET) || (server_addr.sa_family == AF_INET6)))
+ identity_name = query_ident_name(&server_addr,
+ &client_addr);
log_connection(_("connection from"));
open_databases();
diff --git a/dicod/dicod.h b/dicod/dicod.h
index 1260e63..127ff14 100644
--- a/dicod/dicod.h
+++ b/dicod/dicod.h
@@ -335,8 +335,8 @@ void compile_access_log(void);
void access_log_free_cache(void);
/* ident.c */
-char *query_ident_name(struct sockaddr_in *srv_addr,
- struct sockaddr_in *clt_addr);
+char *query_ident_name(struct sockaddr *srv_addr,
+ struct sockaddr *clt_addr);
/* alias.c */
int alias_install(const char *kw, int argc, char **argv, grecs_locus_t *ploc);
diff --git a/dicod/ident.c b/dicod/ident.c
index cf2c18c..5f55849 100644
--- a/dicod/ident.c
+++ b/dicod/ident.c
@@ -371,19 +371,20 @@ socket_io(int fd, int conflag, long timeout,
}
char *
-query_ident_name(struct sockaddr_in *srv_addr, struct sockaddr_in *clt_addr)
+query_ident_name(struct sockaddr *srv_addr, struct sockaddr *clt_addr)
{
int fd;
int rc;
int conflag;
char buf[UINTMAX_STRSIZE_BOUND];
- struct sockaddr_in s;
+ struct sockaddr s;
struct io_buffer ib, ob;
char *name = NULL;
+ char clt_addr_str[NI_MAXHOST];
RETSIGTYPE (*sighan) (int);
enum socket_io_retval retval;
- fd = socket(PF_INET, SOCK_STREAM, 0);
+ fd = socket(srv_addr->sa_family, SOCK_STREAM, 0);
if (fd == -1) {
dico_log(L_ERR, errno,
_("cannot create socket for AUTH identification"));
@@ -393,10 +394,13 @@ query_ident_name(struct sockaddr_in *srv_addr, struct sockaddr_in *clt_addr)
rc |= O_NONBLOCK;
fcntl(fd, F_SETFL, rc);
- s.sin_family = AF_INET;
- s.sin_addr.s_addr = srv_addr->sin_addr.s_addr;
- s.sin_port = 0;
- if (bind(fd, (struct sockaddr*) &s, sizeof(s)) < 0) {
+ s = *srv_addr;
+ if(s.sa_family == AF_INET)
+ ((struct sockaddr_in *) &s)->sin_port = 0;
+ else
+ ((struct sockaddr_in6 *) &s)->sin6_port = 0;
+
+ if (bind(fd, &s, sizeof(s)) < 0) {
dico_log(L_ERR, errno,
_("cannot bind AUTH socket"));
close(fd);
@@ -404,15 +408,19 @@ query_ident_name(struct sockaddr_in *srv_addr, struct sockaddr_in *clt_addr)
}
s = *clt_addr;
- s.sin_port = htons(113);
+ if(s.sa_family == AF_INET)
+ ((struct sockaddr_in *) &s)->sin_port = htons(113);
+ else
+ ((struct sockaddr_in6 *) &s)->sin6_port = htons(113);
- if (connect(fd, (struct sockaddr*) &s, sizeof(s)) == -1) {
+ getnameinfo(&s, sizeof(s), clt_addr_str, NI_MAXHOST, NULL, 0, 0);
+ if (connect(fd, &s, sizeof(s)) == -1) {
if (errno == EINPROGRESS)
conflag = 0;
else {
dico_log(L_ERR, errno,
_("cannot connect to AUTH server %s"),
- inet_ntoa(s.sin_addr));
+ clt_addr_str);
close(fd);
return NULL;
}
@@ -424,8 +432,8 @@ query_ident_name(struct sockaddr_in *srv_addr, struct sockaddr_in *clt_addr)
io_buffer_init(&ib);
io_buffer_init(&ob);
asprintf(&ob.buffer, "%u , %u\r\n",
- ntohs(clt_addr->sin_port),
- ntohs(srv_addr->sin_port));
+ ntohs((clt_addr->sa_family == AF_INET)?((struct sockaddr_in *) clt_addr)->sin_port:((struct sockaddr_in6 *) clt_addr)->sin6_port),
+ ntohs((srv_addr->sa_family == AF_INET)?((struct sockaddr_in *) srv_addr)->sin_port:((struct sockaddr_in6 *) srv_addr)->sin6_port));
ob.size = strlen(ob.buffer);
retval = socket_io(fd, conflag, ident_timeout, &ib, &ob);
@@ -438,7 +446,7 @@ query_ident_name(struct sockaddr_in *srv_addr, struct sockaddr_in *clt_addr)
if (!name) {
dico_log(L_ERR, 0,
_("Malformed IDENT response: `%s', from %s"),
- ib.buffer, inet_ntoa(s.sin_addr));
+ ib.buffer, clt_addr_str);
} else if (is_des_p(name)) {
if (!ident_keyfile) {
dico_log (L_ERR, 0,
@@ -459,24 +467,24 @@ query_ident_name(struct sockaddr_in *srv_addr, struct sockaddr_in *clt_addr)
case socket_io_failure:
dico_log(L_ERR, errno,
_("failure while communicating with AUTH server %s"),
- inet_ntoa(s.sin_addr));
+ clt_addr_str);
break;
case socket_io_connect:
dico_log(L_ERR, errno,
_("cannot connect to AUTH server %s"),
- inet_ntoa(s.sin_addr));
+ clt_addr_str);
break;
case socket_io_noreply:
dico_log(L_ERR, errno, _("no reply from AUTH server %s"),
- inet_ntoa(s.sin_addr));
+ clt_addr_str);
break;
case socket_io_error:
dico_log(L_ERR, errno,
_("I/O error while communicating with AUTH server %s"),
- inet_ntoa(s.sin_addr));
+ clt_addr_str);
}
io_buffer_free(&ib);
diff --git a/dicod/main.c b/dicod/main.c
index 374fa12..cd0c64c 100644
--- a/dicod/main.c
+++ b/dicod/main.c
@@ -1320,7 +1320,7 @@ config_init()
DEFAULT_INCLUDE_DIR, NULL);
grecs_preprocessor = DEFAULT_PREPROCESSOR;
grecs_log_to_stderr = 1;
- grecs_default_port = htons(DICO_DICT_PORT);
+ grecs_default_port = DICO_DICT_PORT;
}
void
diff --git a/dicod/server.c b/dicod/server.c
index eebf6da..be13a08 100644
--- a/dicod/server.c
+++ b/dicod/server.c
@@ -45,6 +45,9 @@ address_family_to_domain (int family)
case AF_INET:
return PF_INET;
+ case AF_INET6:
+ return PF_INET6;
+
default:
abort();
}
@@ -63,26 +66,34 @@ open_sockets()
srvcount = dico_list_count(listen_addr);
if (srvcount == 0) {
/* Provide defaults */
- struct sockaddr_in *s_in = xmalloc(sizeof(*s_in));
-
- sp = xmalloc(sizeof(*sp));
- sp->sa = (struct sockaddr*) s_in;
- sp->len = sizeof(*s_in);
+ struct addrinfo hints, *servinfo, *res;
+ char urlport[6];
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever, TODO: user configurable?
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE; // fill in my IP for me
+ sprintf(urlport, "%d", DICO_DICT_PORT);
+ getaddrinfo(NULL, urlport, &hints, &servinfo);
if (!listen_addr)
listen_addr = xdico_list_create();
- s_in->sin_family = AF_INET;
- s_in->sin_addr.s_addr = INADDR_ANY;
- s_in->sin_port = htons(DICO_DICT_PORT);
- xdico_list_append(listen_addr, sp);
- srvcount = 1;
+
+ sp = xmalloc(sizeof(*sp));
+ for(res=servinfo; res; res = res->ai_next) {
+ sp->sa = (struct sockaddr*) res->ai_addr;
+ sp->len = res->ai_addrlen;
+ xdico_list_append(listen_addr, sp);
+ srvcount++;
+ }
+ freeaddrinfo(servinfo);
}
srvtab = xcalloc(srvcount, sizeof srvtab[0]);
fdmax = 0;
itr = xdico_list_iterator(listen_addr);
for (i = 0, sp = dico_iterator_first(itr); sp;
sp = dico_iterator_next(itr)) {
- int fd = socket(address_family_to_domain(sp->sa->sa_family),
+ int fd = socket(sp->sa->sa_family,
SOCK_STREAM, 0);
if (fd == -1) {
dico_log(L_ERR, errno, "socket");
@@ -117,6 +128,7 @@ open_sockets()
}
case AF_INET:
+ case AF_INET6:
t = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(t));
break;
diff --git a/doc/dico.texi b/doc/dico.texi
index 8c55707..d3a910e 100644
--- a/doc/dico.texi
+++ b/doc/dico.texi
@@ -1067,15 +1067,16 @@ form. The @var{port} part is either a numeric port number or a
symbolic service name which is found in @file{/etc/services} file.
Either of the two parts may be omitted. If @var{host} is omitted,
-it defaults to @samp{0.0.0.0}, which means ``listen on all
-interfaces''. If @var{port} is omitted, it defaults to 2628. In this
-case the colon may be omitted, too.
+it defaults to @samp{0.0.0.0} (for @acronym{IP}v4), @samp{::} (for
+@acronym{IP}v6), which means ``listen on all interfaces''. If @var{port} is
+omitted, it defaults to 2628. In this case the colon may be omitted, too.
Examples:
@example
listen localhost:2628;
listen 127.0.0.1;
+listen [::]:2628;
listen :2628;
@end example
diff --git a/grecs/src/tree.c b/grecs/src/tree.c
index aee196a..ded9941 100644
--- a/grecs/src/tree.c
+++ b/grecs/src/tree.c
@@ -349,63 +349,60 @@ string_to_sockaddr(struct grecs_sockaddr *sp, const char *string,
sp->sa = grecs_malloc(sp->len);
memcpy(sp->sa, &s_un, sp->len);
} else {
- char *p = strchr(string, ':');
+ char *ip6colon = strchr(string, ':');
+ char *p = strrchr(string, ':');
size_t len;
- struct sockaddr_in sa;
+ struct addrinfo hints, *res;
+ char *host;
+ char freep = 0;
- sa.sin_family = AF_INET;
+ if(p && ip6colon && (p > ip6colon) && (*(p-1) != ']'))
+ // this is just an IPv6 numeric address (without port)
+ p = NULL;
+
if (p)
len = p - string;
else
len = strlen(string);
- if (len == 0)
- sa.sin_addr.s_addr = INADDR_ANY;
- else {
- char *host = grecs_malloc(len + 1);
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+
+ host = grecs_malloc(len + 1);
+ if(string[0] == '[') {
+ // IPv6 numeric address, so remove the brackets
+ memcpy(host, string+1, len-2);
+ host[len-2] = 0;
+ }
+ else {
memcpy(host, string, len);
host[len] = 0;
-
- if (string_to_host(&sa.sin_addr, host, locus)) {
- grecs_error(locus, 0,
- _("%s: not a valid IP address or hostname"),
- host);
- grecs_free(host);
- return 1;
- }
- grecs_free(host);
- }
+ }
- if (p) {
- struct servent *serv;
-
- p++;
- serv = getservbyname(p, "tcp");
- if (serv != NULL)
- sa.sin_port = serv->s_port;
+ if (!p) {
+ if (grecs_default_port) {
+ p = grecs_malloc(6);
+ sprintf(p, "%d", grecs_default_port);
+ freep = 1;
+ }
else {
- unsigned long l;
- char *q;
-
- /* Not in services, maybe a number? */
- l = strtoul(p, &q, 0);
-
- if (*q || l > USHRT_MAX) {
- grecs_error(locus, 0,
- _("%s: not a valid port number"), p);
- return 1;
- }
- sa.sin_port = htons(l);
+ // TODO: or maybe just assume that it is zero ?
+ grecs_error(locus, 0, _("missing port number"));
+ grecs_free(host);
+ return 1;
}
- } else if (grecs_default_port)
- sa.sin_port = grecs_default_port;
- else {
- grecs_error(locus, 0, _("missing port number"));
- return 1;
- }
- sp->len = sizeof(sa);
+ }
+ else
+ p++;
+ getaddrinfo(host, p, &hints, &res);
+ sp->len = res->ai_addrlen;
sp->sa = grecs_malloc(sp->len);
- memcpy(sp->sa, &sa, sp->len);
+ memcpy(sp->sa, res->ai_addr, sp->len);
+
+ freeaddrinfo(res);
+ grecs_free(host);
+ if(freep)
+ grecs_free(p);
}
return 0;
}
signature.asc
Description: Digital signature

