Skip to content

Commit

Permalink
New option "afp interfaces"
Browse files Browse the repository at this point in the history
Allows specifying where Netatalk listens for AFP connections
by interface name, from FR #79.
  • Loading branch information
slowfranklin committed May 14, 2013
1 parent d57dffc commit 21058d4
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 17 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ Changes in 3.0.4
* FIX: Add missing include, fixes bug #512.
* FIX: Change default FinderInfo for directories to be all 0, fixes
bug 514.
* NEW: New option "afp interfaces" which allows specifying where
Netatalk listens for AFP connections by interface names.
From FR #79.

Changes in 3.0.3
================
Expand Down
2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ AC_CHECK_FUNCS(mmap utime getpagesize) dnl needed by tbd
dnl search for necessary libraries
AC_SEARCH_LIBS(gethostbyname, nsl)
AC_SEARCH_LIBS(connect, socket)
AC_CHECK_FUNCS(getifaddrs) dnl comes after gethostbyname and connect so it picks up the libs

AX_PTHREAD(, [AC_MSG_ERROR([missing pthread_sigmask])])

AC_DEFINE(OPEN_NOFOLLOW_ERRNO, ELOOP, errno returned by open with O_NOFOLLOW)
Expand Down
10 changes: 10 additions & 0 deletions doc/manpages/man5/afp.conf.5.xml
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,16 @@
</listitem>
</varlistentry>

<varlistentry>
<term>afp interfaces = <replaceable>name [name ...]</replaceable>
<type>(G)</type></term>
<listitem>
<para>Specifies the network interfaces that the server should
listens on. The default is advertise the first IP address of the
system, but to listen for any incoming request.</para>
</listitem>
</varlistentry>

<varlistentry>
<term>afp listen = <replaceable>ip address[:port] [ip address[:port]
...]</replaceable> <type>(G)</type></term>
Expand Down
108 changes: 92 additions & 16 deletions etc/afpd/afp_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef HAVE_GETIFADDRS
#include <ifaddrs.h>
#endif

#include <atalk/logger.h>
#include <atalk/util.h>
Expand All @@ -39,7 +42,6 @@
#include "volume.h"
#include "afp_zeroconf.h"


/*!
* Free and cleanup config and DSI
*
Expand Down Expand Up @@ -83,33 +85,113 @@ void configfree(AFPObj *obj, DSI *dsi)
int configinit(AFPObj *obj)
{
EC_INIT;
DSI *dsi, **next = &obj->dsi;
DSI *dsi = NULL;
DSI **next = &obj->dsi;
char *p = NULL, *q = NULL, *savep;
const char *r;
struct ifaddrs *ifaddr, *ifa;
int family, s;
static char interfaddr[NI_MAXHOST];

auth_load(obj->options.uampath, obj->options.uamlist);
set_signature(&obj->options);
#ifdef HAVE_LDAP
acl_ldap_freeconfig();
#endif /* HAVE_LDAP */

LOG(log_debug, logtype_afpd, "DSIConfigInit: hostname: %s, listen: %s, port: %s",
LOG(log_debug, logtype_afpd, "DSIConfigInit: hostname: %s, listen: %s, interfaces: %s, port: %s",
obj->options.hostname,
obj->options.listen ? obj->options.listen : "(default: hostname)",
obj->options.listen ? obj->options.listen : "-",
obj->options.interfaces ? obj->options.interfaces : "-",
obj->options.port);

/* obj->options->listen is of the from "IP[:port][,IP:[PORT], ...]" */
/* obj->options->port is the default port to listen (548) */

/*
* Setup addresses we listen on from hostname and/or "afp listen" option
*/
if (obj->options.listen) {
EC_NULL( q = p = strdup(obj->options.listen) );
EC_NULL( p = strtok_r(p, ", ", &savep) );
while (p) {
if ((dsi = dsi_init(obj, obj->options.hostname, p, obj->options.port)) == NULL)
break;

status_init(obj, dsi);
*next = dsi;
next = &dsi->next;
dsi->AFPobj = obj;

LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on %s:%d",
getip_string((struct sockaddr *)&dsi->server),
getip_port((struct sockaddr *)&dsi->server));

p = strtok_r(NULL, ", ", &savep);
}
if (q) {
free(q);
q = NULL;
}
}

while (1) {
if ((dsi = dsi_init(obj, obj->options.hostname, p, obj->options.port)) == NULL)
break;
/*
* Setup addresses we listen on from "afp interfaces".
* We use getifaddrs() instead of if_nameindex() because the latter appears still
* to be unable to return ipv4 addresses
*/
if (obj->options.interfaces) {
#ifndef HAVE_GETIFADDRS
LOG(log_error, logtype_afpd, "option \"afp interfaces\" not supported");
#else
if (getifaddrs(&ifaddr) == -1) {
LOG(log_error, logtype_afpd, "getinterfaddr: getifaddrs() failed: %s", strerror(errno));
EC_FAIL;
}

EC_NULL( q = p = strdup(obj->options.interfaces) );
EC_NULL( p = strtok_r(p, ", ", &savep) );
while (p) {
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
if (STRCMP(ifa->ifa_name, !=, p))
continue;

family = ifa->ifa_addr->sa_family;
if (family == AF_INET || family == AF_INET6) {
if (getnameinfo(ifa->ifa_addr,
(family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
interfaddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) {
LOG(log_error, logtype_afpd, "getinterfaddr: getnameinfo() failed %s", gai_strerror(errno));
continue;
}

if ((dsi = dsi_init(obj, obj->options.hostname, interfaddr, obj->options.port)) == NULL)
continue;

status_init(obj, dsi);
*next = dsi;
next = &dsi->next;
dsi->AFPobj = obj;

LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on interface %s with address %s:%d",
p,
getip_string((struct sockaddr *)&dsi->server),
getip_port((struct sockaddr *)&dsi->server));
} /* if (family == AF_INET || family == AF_INET6) */
} /* for (ifa != NULL) */
p = strtok_r(NULL, ", ", &savep);
}
freeifaddrs(ifaddr);
#endif
}

/*
* Check whether we got a valid DSI from options.listen or options.interfaces,
* if not add a DSI that accepts all connections and goes though the list of
* network interaces for determining an IP we can advertise in DSIStatus
*/
if (dsi == NULL) {
if ((dsi = dsi_init(obj, obj->options.hostname, NULL, obj->options.port)) == NULL)
EC_FAIL_LOG("no suitable network address found, use \"afp listen\" or \"afp interfaces\"", 0);
status_init(obj, dsi);
*next = dsi;
next = &dsi->next;
Expand All @@ -118,12 +200,6 @@ int configinit(AFPObj *obj)
LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on %s:%d",
getip_string((struct sockaddr *)&dsi->server),
getip_port((struct sockaddr *)&dsi->server));

if (p)
/* p is NULL if ! obj->options.listen */
p = strtok_r(NULL, ", ", &savep);
if (!p)
break;
}

#ifdef HAVE_LDAP
Expand Down
2 changes: 1 addition & 1 deletion include/atalk/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ struct afp_options {
uint32_t server_quantum;
int dsireadbuf; /* scale factor for sizefof(dsi->buffer) = server_quantum * dsireadbuf */
char *hostname;
char *listen, *port;
char *listen, *interfaces, *port;
char *Cnid_srv, *Cnid_port;
char *configfile;
char *uampath, *fqdn;
Expand Down
3 changes: 3 additions & 0 deletions libatalk/util/netatalk_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1740,6 +1740,7 @@ int afp_config_parse(AFPObj *AFPObj, char *processname)
options->k5service = iniparser_getstrdup(config, INISEC_GLOBAL, "k5 service", NULL);
options->k5realm = iniparser_getstrdup(config, INISEC_GLOBAL, "k5 realm", NULL);
options->listen = iniparser_getstrdup(config, INISEC_GLOBAL, "afp listen", NULL);
options->interfaces = iniparser_getstrdup(config, INISEC_GLOBAL, "afp interfaces", NULL);
options->ntdomain = iniparser_getstrdup(config, INISEC_GLOBAL, "nt domain", NULL);
options->addomain = iniparser_getstrdup(config, INISEC_GLOBAL, "ad domain", NULL);
options->ntseparator = iniparser_getstrdup(config, INISEC_GLOBAL, "nt separator", NULL);
Expand Down Expand Up @@ -1941,6 +1942,8 @@ void afp_config_free(AFPObj *obj)
CONFIG_ARG_FREE(obj->options.k5realm);
if (obj->options.listen)
CONFIG_ARG_FREE(obj->options.listen);
if (obj->options.interfaces)
CONFIG_ARG_FREE(obj->options.interfaces);
if (obj->options.ntdomain)
CONFIG_ARG_FREE(obj->options.ntdomain);
if (obj->options.addomain)
Expand Down
5 changes: 5 additions & 0 deletions man/man5/afp.conf.5.in
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,11 @@ Setting this option is not recommended since globally encrypting AFP connections
.RE
.RE
.PP
afp interfaces = \fIname [name \&.\&.\&.]\fR \fB(G)\fR
.RS 4
Specifies the network interfaces that the server should listens on\&. The default is advertise the first IP address of the system, but to listen for any incoming request\&.
.RE
.PP
afp listen = \fIip address[:port] [ip address[:port] \&.\&.\&.]\fR \fB(G)\fR
.RS 4
Specifies the IP address that the server should advertise
Expand Down

0 comments on commit 21058d4

Please sign in to comment.