mirror of
https://github.com/samba-team/samba.git
synced 2025-01-12 09:18:10 +03:00
Fix resolve name to resolve IPv6 addresses of link-local%ifaddr
Jeremy.
This commit is contained in:
parent
2df8252ff7
commit
e6609cab73
@ -88,6 +88,29 @@ bool is_local_net(const struct sockaddr_storage *from)
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(HAVE_IPV6)
|
||||
void setup_linklocal_scope_id(struct sockaddr_storage *pss)
|
||||
{
|
||||
struct interface *i;
|
||||
for (i=local_interfaces;i;i=i->next) {
|
||||
if (addr_equal(&i->ip,pss)) {
|
||||
struct sockaddr_in6 *psa6 =
|
||||
(struct sockaddr_in6 *)pss;
|
||||
psa6->sin6_scope_id = if_nametoindex(i->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (i=local_interfaces;i;i=i->next) {
|
||||
if (same_net(pss, &i->ip, &i->netmask)) {
|
||||
struct sockaddr_in6 *psa6 =
|
||||
(struct sockaddr_in6 *)pss;
|
||||
psa6->sin6_scope_id = if_nametoindex(i->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
Check if a packet is from a local (known) net.
|
||||
**************************************************************************/
|
||||
@ -325,100 +348,6 @@ static void add_interface(const struct iface_struct *ifs)
|
||||
&iface->netmask) ));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Create a struct sockaddr_storage with the netmask bits set to 1.
|
||||
****************************************************************************/
|
||||
|
||||
bool make_netmask(struct sockaddr_storage *pss_out,
|
||||
const struct sockaddr_storage *pss_in,
|
||||
unsigned long masklen)
|
||||
{
|
||||
*pss_out = *pss_in;
|
||||
/* Now apply masklen bits of mask. */
|
||||
#if defined(HAVE_IPV6)
|
||||
if (pss_in->ss_family == AF_INET6) {
|
||||
char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
|
||||
unsigned int i;
|
||||
|
||||
if (masklen > 128) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; masklen >= 8; masklen -= 8, i++) {
|
||||
*p++ = 0xff;
|
||||
}
|
||||
/* Deal with the partial byte. */
|
||||
*p++ &= (0xff & ~(0xff>>masklen));
|
||||
i++;
|
||||
for (;i < sizeof(struct in6_addr); i++) {
|
||||
*p++ = '\0';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (pss_in->ss_family == AF_INET) {
|
||||
if (masklen > 32) {
|
||||
return false;
|
||||
}
|
||||
((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
|
||||
htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Create a struct sockaddr_storage set to the broadcast or network adress from
|
||||
an incoming sockaddr_storage.
|
||||
****************************************************************************/
|
||||
|
||||
static void make_bcast_or_net(struct sockaddr_storage *pss_out,
|
||||
const struct sockaddr_storage *pss_in,
|
||||
const struct sockaddr_storage *nmask,
|
||||
bool make_bcast)
|
||||
{
|
||||
unsigned int i = 0, len = 0;
|
||||
char *pmask = NULL;
|
||||
char *p = NULL;
|
||||
*pss_out = *pss_in;
|
||||
|
||||
/* Set all zero netmask bits to 1. */
|
||||
#if defined(HAVE_IPV6)
|
||||
if (pss_in->ss_family == AF_INET6) {
|
||||
p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
|
||||
pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr;
|
||||
len = 16;
|
||||
}
|
||||
#endif
|
||||
if (pss_in->ss_family == AF_INET) {
|
||||
p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
|
||||
pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr;
|
||||
len = 4;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++, p++, pmask++) {
|
||||
if (make_bcast) {
|
||||
*p = (*p & *pmask) | (*pmask ^ 0xff);
|
||||
} else {
|
||||
/* make_net */
|
||||
*p = (*p & *pmask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void make_bcast(struct sockaddr_storage *pss_out,
|
||||
const struct sockaddr_storage *pss_in,
|
||||
const struct sockaddr_storage *nmask)
|
||||
{
|
||||
make_bcast_or_net(pss_out, pss_in, nmask, true);
|
||||
}
|
||||
|
||||
static void make_net(struct sockaddr_storage *pss_out,
|
||||
const struct sockaddr_storage *pss_in,
|
||||
const struct sockaddr_storage *nmask)
|
||||
{
|
||||
make_bcast_or_net(pss_out, pss_in, nmask, false);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Interpret a single element from a interfaces= config line.
|
||||
|
||||
|
@ -87,6 +87,104 @@
|
||||
#include "interfaces.h"
|
||||
#include "lib/replace/replace.h"
|
||||
|
||||
/****************************************************************************
|
||||
Utility functions.
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
Create a struct sockaddr_storage with the netmask bits set to 1.
|
||||
****************************************************************************/
|
||||
|
||||
bool make_netmask(struct sockaddr_storage *pss_out,
|
||||
const struct sockaddr_storage *pss_in,
|
||||
unsigned long masklen)
|
||||
{
|
||||
*pss_out = *pss_in;
|
||||
/* Now apply masklen bits of mask. */
|
||||
#if defined(HAVE_IPV6)
|
||||
if (pss_in->ss_family == AF_INET6) {
|
||||
char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
|
||||
unsigned int i;
|
||||
|
||||
if (masklen > 128) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; masklen >= 8; masklen -= 8, i++) {
|
||||
*p++ = 0xff;
|
||||
}
|
||||
/* Deal with the partial byte. */
|
||||
*p++ &= (0xff & ~(0xff>>masklen));
|
||||
i++;
|
||||
for (;i < sizeof(struct in6_addr); i++) {
|
||||
*p++ = '\0';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (pss_in->ss_family == AF_INET) {
|
||||
if (masklen > 32) {
|
||||
return false;
|
||||
}
|
||||
((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
|
||||
htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Create a struct sockaddr_storage set to the broadcast or network adress from
|
||||
an incoming sockaddr_storage.
|
||||
****************************************************************************/
|
||||
|
||||
static void make_bcast_or_net(struct sockaddr_storage *pss_out,
|
||||
const struct sockaddr_storage *pss_in,
|
||||
const struct sockaddr_storage *nmask,
|
||||
bool make_bcast)
|
||||
{
|
||||
unsigned int i = 0, len = 0;
|
||||
char *pmask = NULL;
|
||||
char *p = NULL;
|
||||
*pss_out = *pss_in;
|
||||
|
||||
/* Set all zero netmask bits to 1. */
|
||||
#if defined(HAVE_IPV6)
|
||||
if (pss_in->ss_family == AF_INET6) {
|
||||
p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
|
||||
pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr;
|
||||
len = 16;
|
||||
}
|
||||
#endif
|
||||
if (pss_in->ss_family == AF_INET) {
|
||||
p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
|
||||
pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr;
|
||||
len = 4;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++, p++, pmask++) {
|
||||
if (make_bcast) {
|
||||
*p = (*p & *pmask) | (*pmask ^ 0xff);
|
||||
} else {
|
||||
/* make_net */
|
||||
*p = (*p & *pmask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void make_bcast(struct sockaddr_storage *pss_out,
|
||||
const struct sockaddr_storage *pss_in,
|
||||
const struct sockaddr_storage *nmask)
|
||||
{
|
||||
make_bcast_or_net(pss_out, pss_in, nmask, true);
|
||||
}
|
||||
|
||||
void make_net(struct sockaddr_storage *pss_out,
|
||||
const struct sockaddr_storage *pss_in,
|
||||
const struct sockaddr_storage *nmask)
|
||||
{
|
||||
make_bcast_or_net(pss_out, pss_in, nmask, false);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Try the "standard" getifaddrs/freeifaddrs interfaces.
|
||||
Also gets IPv6 interfaces.
|
||||
@ -137,11 +235,20 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
|
||||
memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
|
||||
memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
|
||||
|
||||
if ((ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) &&
|
||||
ifptr->ifa_broadaddr) {
|
||||
memcpy(&ifaces[total].bcast,
|
||||
ifptr->ifa_broadaddr,
|
||||
copy_size);
|
||||
if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) {
|
||||
if (ifptr->ifa_broadaddr) {
|
||||
memcpy(&ifaces[total].bcast,
|
||||
ifptr->ifa_broadaddr,
|
||||
copy_size);
|
||||
} else {
|
||||
/* For some reason ifptr->ifa_broadaddr
|
||||
* is null. Make one from ifa_addr and
|
||||
* ifa_netmask.
|
||||
*/
|
||||
make_bcast(&ifaces[total].bcast,
|
||||
&ifaces[total].ip,
|
||||
&ifaces[total].netmask);
|
||||
}
|
||||
} else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
|
||||
ifptr->ifa_dstaddr ) {
|
||||
memcpy(&ifaces[total].bcast,
|
||||
|
@ -64,7 +64,7 @@ bool is_ipaddress(const char *str)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Is a sockaddr_storage a broadcast address ?
|
||||
Is a sockaddr_storage a broadcast address ?
|
||||
****************************************************************************/
|
||||
|
||||
bool is_broadcast_addr(const struct sockaddr_storage *pss)
|
||||
@ -1478,6 +1478,10 @@ int open_socket_out(int type,
|
||||
if (pss->ss_family == AF_INET6) {
|
||||
struct sockaddr_in6 *psa6 = (struct sockaddr_in6 *)&sock_out;
|
||||
psa6->sin6_port = htons(port);
|
||||
if (psa6->sin6_scope_id == 0 &&
|
||||
IN6_IS_ADDR_LINKLOCAL(&psa6->sin6_addr)) {
|
||||
setup_linklocal_scope_id(&sock_out);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (pss->ss_family == AF_INET) {
|
||||
|
@ -1594,6 +1594,32 @@ bool resolve_name(const char *name,
|
||||
char *sitename = NULL;
|
||||
int count = 0;
|
||||
|
||||
#if defined(HAVE_IPV6)
|
||||
unsigned int if_idx = 0;
|
||||
const char *p = strchr_m(name, '%');
|
||||
|
||||
if (p && (if_idx = if_nametoindex(p+1)) != 0) {
|
||||
char *newname = SMB_STRDUP(name);
|
||||
if (!newname) {
|
||||
return false;
|
||||
}
|
||||
newname[PTR_DIFF(p,name)] = '\0';
|
||||
if (is_ipaddress(newname) &&
|
||||
interpret_string_addr(return_ss,
|
||||
newname, AI_NUMERICHOST)) {
|
||||
struct sockaddr_in6 *psa6 =
|
||||
(struct sockaddr_in6 *)&return_ss;
|
||||
if (psa6->sin6_scope_id == 0 &&
|
||||
IN6_IS_ADDR_LINKLOCAL(&psa6->sin6_addr)) {
|
||||
psa6->sin6_scope_id = if_idx;
|
||||
}
|
||||
SAFE_FREE(newname);
|
||||
return true;
|
||||
}
|
||||
SAFE_FREE(newname);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (is_ipaddress(name)) {
|
||||
return interpret_string_addr(return_ss, name, AI_NUMERICHOST);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user