Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
D
Dnsmasq
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nanahira
Dnsmasq
Commits
ff7eea27
Commit
ff7eea27
authored
Sep 04, 2013
by
Simon Kelley
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add --dhcp-relay config option.
parent
6692a1a5
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
545 additions
and
193 deletions
+545
-193
CHANGELOG
CHANGELOG
+2
-0
man/dnsmasq.8
man/dnsmasq.8
+32
-0
src/dhcp-common.c
src/dhcp-common.c
+11
-1
src/dhcp.c
src/dhcp.c
+160
-46
src/dhcp6.c
src/dhcp6.c
+128
-93
src/dnsmasq.c
src/dnsmasq.c
+47
-43
src/dnsmasq.h
src/dnsmasq.h
+11
-0
src/netlink.c
src/netlink.c
+5
-5
src/network.c
src/network.c
+1
-1
src/option.c
src/option.c
+28
-0
src/outpacket.c
src/outpacket.c
+2
-2
src/rfc3315.c
src/rfc3315.c
+118
-2
No files found.
CHANGELOG
View file @
ff7eea27
...
@@ -101,6 +101,8 @@ version 2.67
...
@@ -101,6 +101,8 @@ version 2.67
(provide TFTP to the same interfaces we provide DHCP to)
(provide TFTP to the same interfaces we provide DHCP to)
is retained. Thanks to Lonnie Abelbeck for the suggestion.
is retained. Thanks to Lonnie Abelbeck for the suggestion.
Add --dhcp-relay config option.
version 2.66
version 2.66
Add the ability to act as an authoritative DNS
Add the ability to act as an authoritative DNS
...
...
man/dnsmasq.8
View file @
ff7eea27
...
@@ -973,6 +973,38 @@ DHCP options. This make extra space available in the DHCP packet for
...
@@ -973,6 +973,38 @@ DHCP options. This make extra space available in the DHCP packet for
options but can, rarely, confuse old or broken clients. This flag
options but can, rarely, confuse old or broken clients. This flag
forces "simple and safe" behaviour to avoid problems in such a case.
forces "simple and safe" behaviour to avoid problems in such a case.
.TP
.TP
.B --dhcp-relay=<local address>,<server address>[,<interface]
Configure dnsmasq to do DHCP relay. The local address is an address
allocated to an interface on the host running dnsmasq. All DHCP
requests arriving on that interface will we relayed to a remote DHCP
server at the server address. It is possible to relay from a single local
address to multiple remote servers by using multiple dhcp-relay
configs with the same local address and different server
addresses. A server address must be an IP literal address, not a
domain name. In the case of DHCPv6, the server address may be the
ALL_SERVERS multicast address, ff05::1:3. In this case the interface
must be given, not be wildcard, and is used to direct the multicast to the
correct interface to reach the DHCP server.
Access control for DHCP clients has the same rules as for the DHCP
server, see --interface, --except-interface, etc. The optional
interface name in the dhcp-relay config has a different function: it
controls on which interface DHCP replies from the server will be
accepted. This is intended for configurations which have three
interfaces: one being relayed from, a second connecting the DHCP
server, and a third untrusted network, typically the wider
internet. It avoids the possibility of spoof replies arriving via this
third interface.
It is allowed to have dnsmasq act as a DHCP server on one set of
interfaces and relay from a disjoint set of interfaces. Note that
whilst it is quite possible to write configurations which appear to
act as a server and a relay on the same interface, this is not
supported: the relay function will take precedence.
Both DHCPv4 and DHCPv6 relay is supported. It's not possible to relay
DHCPv4 to a DHCPv6 server or vice-versa.
.TP
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
Map from a vendor-class string to a tag. Most DHCP clients provide a
Map from a vendor-class string to a tag. Most DHCP clients provide a
"vendor class" which represents, in some sense, the type of host. This option
"vendor class" which represents, in some sense, the type of host. This option
...
...
src/dhcp-common.c
View file @
ff7eea27
...
@@ -757,6 +757,16 @@ void log_context(int family, struct dhcp_context *context)
...
@@ -757,6 +757,16 @@ void log_context(int family, struct dhcp_context *context)
#endif
#endif
}
}
void
log_relay
(
int
family
,
struct
dhcp_relay
*
relay
)
{
inet_ntop
(
family
,
&
relay
->
local
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
inet_ntop
(
family
,
&
relay
->
server
,
daemon
->
namebuff
,
ADDRSTRLEN
);
if
(
relay
->
interface
)
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"DHCP relay from %s to %s via %s"
),
daemon
->
addrbuff
,
daemon
->
namebuff
,
relay
->
interface
);
else
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"DHCP relay from %s to %s"
),
daemon
->
addrbuff
,
daemon
->
namebuff
);
}
#endif
#endif
src/dhcp.c
View file @
ff7eea27
...
@@ -20,6 +20,8 @@
...
@@ -20,6 +20,8 @@
struct
iface_param
{
struct
iface_param
{
struct
dhcp_context
*
current
;
struct
dhcp_context
*
current
;
struct
dhcp_relay
*
relay
;
struct
in_addr
relay_local
;
int
ind
;
int
ind
;
};
};
...
@@ -32,6 +34,8 @@ static int complete_context(struct in_addr local, int if_index, char *label,
...
@@ -32,6 +34,8 @@ static int complete_context(struct in_addr local, int if_index, char *label,
struct
in_addr
netmask
,
struct
in_addr
broadcast
,
void
*
vparam
);
struct
in_addr
netmask
,
struct
in_addr
broadcast
,
void
*
vparam
);
static
int
check_listen_addrs
(
struct
in_addr
local
,
int
if_index
,
char
*
label
,
static
int
check_listen_addrs
(
struct
in_addr
local
,
int
if_index
,
char
*
label
,
struct
in_addr
netmask
,
struct
in_addr
broadcast
,
void
*
vparam
);
struct
in_addr
netmask
,
struct
in_addr
broadcast
,
void
*
vparam
);
static
int
relay_upstream4
(
struct
dhcp_relay
*
relay
,
struct
dhcp_packet
*
mess
,
size_t
sz
,
int
iface_index
);
static
struct
dhcp_relay
*
relay_reply4
(
struct
dhcp_packet
*
mess
,
char
*
arrival_interface
);
static
int
make_fd
(
int
port
)
static
int
make_fd
(
int
port
)
{
{
...
@@ -132,6 +136,8 @@ void dhcp_packet(time_t now, int pxe_fd)
...
@@ -132,6 +136,8 @@ void dhcp_packet(time_t now, int pxe_fd)
int
fd
=
pxe_fd
?
daemon
->
pxefd
:
daemon
->
dhcpfd
;
int
fd
=
pxe_fd
?
daemon
->
pxefd
:
daemon
->
dhcpfd
;
struct
dhcp_packet
*
mess
;
struct
dhcp_packet
*
mess
;
struct
dhcp_context
*
context
;
struct
dhcp_context
*
context
;
struct
dhcp_relay
*
relay
;
int
is_relay_reply
=
0
;
struct
iname
*
tmp
;
struct
iname
*
tmp
;
struct
ifreq
ifr
;
struct
ifreq
ifr
;
struct
msghdr
msg
;
struct
msghdr
msg
;
...
@@ -250,57 +256,86 @@ void dhcp_packet(time_t now, int pxe_fd)
...
@@ -250,57 +256,86 @@ void dhcp_packet(time_t now, int pxe_fd)
unicast_dest
=
1
;
unicast_dest
=
1
;
#endif
#endif
ifr
.
ifr_addr
.
sa_family
=
AF_INET
;
if
((
relay
=
relay_reply4
((
struct
dhcp_packet
*
)
daemon
->
dhcp_packet
.
iov_base
,
ifr
.
ifr_name
)))
if
(
ioctl
(
daemon
->
dhcpfd
,
SIOCGIFADDR
,
&
ifr
)
!=
-
1
)
iface_addr
=
((
struct
sockaddr_in
*
)
&
ifr
.
ifr_addr
)
->
sin_addr
;
else
{
{
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"DHCP packet received on %s which has no address"
),
ifr
.
ifr_name
);
/* Reply from server, using us as relay. */
return
;
iface_index
=
relay
->
iface_index
;
if
(
!
indextoname
(
daemon
->
dhcpfd
,
iface_index
,
ifr
.
ifr_name
))
return
;
is_relay_reply
=
1
;
iov
.
iov_len
=
sz
;
#ifdef HAVE_LINUX_NETWORK
strncpy
(
arp_req
.
arp_dev
,
ifr
.
ifr_name
,
16
);
#endif
}
}
else
for
(
tmp
=
daemon
->
dhcp_except
;
tmp
;
tmp
=
tmp
->
next
)
if
(
tmp
->
name
&&
wildcard_match
(
tmp
->
name
,
ifr
.
ifr_name
))
return
;
/* unlinked contexts are marked by context->current == context */
for
(
context
=
daemon
->
dhcp
;
context
;
context
=
context
->
next
)
context
->
current
=
context
;
parm
.
current
=
NULL
;
parm
.
ind
=
iface_index
;
if
(
!
iface_check
(
AF_INET
,
(
struct
all_addr
*
)
&
iface_addr
,
ifr
.
ifr_name
,
NULL
))
{
{
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
ifr
.
ifr_addr
.
sa_family
=
AF_INET
;
for a secondary */
if
(
ioctl
(
daemon
->
dhcpfd
,
SIOCGIFADDR
,
&
ifr
)
!=
-
1
)
struct
match_param
match
;
iface_addr
=
((
struct
sockaddr_in
*
)
&
ifr
.
ifr_addr
)
->
sin_addr
;
else
{
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"DHCP packet received on %s which has no address"
),
ifr
.
ifr_name
);
return
;
}
for
(
tmp
=
daemon
->
dhcp_except
;
tmp
;
tmp
=
tmp
->
next
)
if
(
tmp
->
name
&&
wildcard_match
(
tmp
->
name
,
ifr
.
ifr_name
))
return
;
/* unlinked contexts/relays are marked by context->current == context */
for
(
context
=
daemon
->
dhcp
;
context
;
context
=
context
->
next
)
context
->
current
=
context
;
for
(
relay
=
daemon
->
relay4
;
relay
;
relay
=
relay
->
next
)
relay
->
current
=
relay
;
match
.
matched
=
0
;
parm
.
current
=
NULL
;
match
.
ind
=
iface_index
;
parm
.
relay
=
NULL
;
parm
.
relay_local
.
s_addr
=
0
;
parm
.
ind
=
iface_index
;
if
(
!
daemon
->
if_addrs
||
if
(
!
iface_check
(
AF_INET
,
(
struct
all_addr
*
)
&
iface_addr
,
ifr
.
ifr_name
,
NULL
))
!
iface_enumerate
(
AF_INET
,
&
match
,
check_listen_addrs
)
||
{
!
match
.
matched
)
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
for a secondary */
struct
match_param
match
;
match
.
matched
=
0
;
match
.
ind
=
iface_index
;
if
(
!
daemon
->
if_addrs
||
!
iface_enumerate
(
AF_INET
,
&
match
,
check_listen_addrs
)
||
!
match
.
matched
)
return
;
iface_addr
=
match
.
addr
;
/* make sure secondary address gets priority in case
there is more than one address on the interface in the same subnet */
complete_context
(
match
.
addr
,
iface_index
,
NULL
,
match
.
netmask
,
match
.
broadcast
,
&
parm
);
}
if
(
!
iface_enumerate
(
AF_INET
,
&
parm
,
complete_context
))
return
;
/* We're relaying this request */
if
(
parm
.
relay_local
.
s_addr
!=
0
&&
relay_upstream4
(
parm
.
relay
,
(
struct
dhcp_packet
*
)
daemon
->
dhcp_packet
.
iov_base
,
(
size_t
)
sz
,
iface_index
))
return
;
/* May have configured relay, but not DHCP server */
if
(
!
daemon
->
dhcp
)
return
;
return
;
iface_addr
=
match
.
addr
;
lease_prune
(
NULL
,
now
);
/* lose any expired leases */
/* make sure secondary address gets priority in case
iov
.
iov_len
=
dhcp_reply
(
parm
.
current
,
ifr
.
ifr_name
,
iface_index
,
(
size_t
)
sz
,
there is more than one address on the interface in the same subnet */
now
,
unicast_dest
,
&
is_inform
,
pxe_fd
,
iface_addr
);
complete_context
(
match
.
addr
,
iface_index
,
NULL
,
match
.
netmask
,
match
.
broadcast
,
&
parm
);
lease_update_file
(
now
);
}
lease_update_dns
(
0
);
if
(
!
iface_enumerate
(
AF_INET
,
&
parm
,
complete_context
))
if
(
iov
.
iov_len
==
0
)
return
;
return
;
}
lease_prune
(
NULL
,
now
);
/* lose any expired leases */
iov
.
iov_len
=
dhcp_reply
(
parm
.
current
,
ifr
.
ifr_name
,
iface_index
,
(
size_t
)
sz
,
now
,
unicast_dest
,
&
is_inform
,
pxe_fd
,
iface_addr
);
lease_update_file
(
now
);
lease_update_dns
(
0
);
if
(
iov
.
iov_len
==
0
)
return
;
msg
.
msg_name
=
&
dest
;
msg
.
msg_name
=
&
dest
;
msg
.
msg_namelen
=
sizeof
(
dest
);
msg
.
msg_namelen
=
sizeof
(
dest
);
...
@@ -321,7 +356,7 @@ void dhcp_packet(time_t now, int pxe_fd)
...
@@ -321,7 +356,7 @@ void dhcp_packet(time_t now, int pxe_fd)
if
(
mess
->
ciaddr
.
s_addr
!=
0
)
if
(
mess
->
ciaddr
.
s_addr
!=
0
)
dest
.
sin_addr
=
mess
->
ciaddr
;
dest
.
sin_addr
=
mess
->
ciaddr
;
}
}
else
if
(
mess
->
giaddr
.
s_addr
)
else
if
(
mess
->
giaddr
.
s_addr
&&
!
is_relay_reply
)
{
{
/* Send to BOOTP relay */
/* Send to BOOTP relay */
dest
.
sin_port
=
htons
(
daemon
->
dhcp_server_port
);
dest
.
sin_port
=
htons
(
daemon
->
dhcp_server_port
);
...
@@ -334,7 +369,7 @@ void dhcp_packet(time_t now, int pxe_fd)
...
@@ -334,7 +369,7 @@ void dhcp_packet(time_t now, int pxe_fd)
source port too, and send back to that. If we're replying
source port too, and send back to that. If we're replying
to a DHCPINFORM, trust the source address always. */
to a DHCPINFORM, trust the source address always. */
if
((
!
is_inform
&&
dest
.
sin_addr
.
s_addr
!=
mess
->
ciaddr
.
s_addr
)
||
if
((
!
is_inform
&&
dest
.
sin_addr
.
s_addr
!=
mess
->
ciaddr
.
s_addr
)
||
dest
.
sin_port
==
0
||
dest
.
sin_addr
.
s_addr
==
0
)
dest
.
sin_port
==
0
||
dest
.
sin_addr
.
s_addr
==
0
||
is_relay_reply
)
{
{
dest
.
sin_port
=
htons
(
daemon
->
dhcp_client_port
);
dest
.
sin_port
=
htons
(
daemon
->
dhcp_client_port
);
dest
.
sin_addr
=
mess
->
ciaddr
;
dest
.
sin_addr
=
mess
->
ciaddr
;
...
@@ -450,6 +485,7 @@ static int complete_context(struct in_addr local, int if_index, char *label,
...
@@ -450,6 +485,7 @@ static int complete_context(struct in_addr local, int if_index, char *label,
struct
in_addr
netmask
,
struct
in_addr
broadcast
,
void
*
vparam
)
struct
in_addr
netmask
,
struct
in_addr
broadcast
,
void
*
vparam
)
{
{
struct
dhcp_context
*
context
;
struct
dhcp_context
*
context
;
struct
dhcp_relay
*
relay
;
struct
iface_param
*
param
=
vparam
;
struct
iface_param
*
param
=
vparam
;
(
void
)
label
;
(
void
)
label
;
...
@@ -495,6 +531,15 @@ static int complete_context(struct in_addr local, int if_index, char *label,
...
@@ -495,6 +531,15 @@ static int complete_context(struct in_addr local, int if_index, char *label,
}
}
}
}
for
(
relay
=
daemon
->
relay4
;
relay
;
relay
=
relay
->
next
)
if
(
if_index
==
param
->
ind
&&
relay
->
local
.
addr
.
addr4
.
s_addr
==
local
.
s_addr
&&
relay
->
current
==
relay
&&
(
param
->
relay_local
.
s_addr
==
0
||
param
->
relay_local
.
s_addr
==
local
.
s_addr
))
{
relay
->
current
=
param
->
relay
;
param
->
relay
=
relay
;
param
->
relay_local
=
local
;
}
return
1
;
return
1
;
}
}
...
@@ -988,5 +1033,74 @@ char *host_from_dns(struct in_addr addr)
...
@@ -988,5 +1033,74 @@ char *host_from_dns(struct in_addr addr)
return
NULL
;
return
NULL
;
}
}
#endif
static
int
relay_upstream4
(
struct
dhcp_relay
*
relay
,
struct
dhcp_packet
*
mess
,
size_t
sz
,
int
iface_index
)
{
/* ->local is same value for all relays on ->current chain */
struct
all_addr
from
;
if
(
mess
->
op
!=
BOOTREQUEST
)
return
0
;
/* source address == relay address */
from
.
addr
.
addr4
=
relay
->
local
.
addr
.
addr4
;
/* already gatewayed ? */
if
(
mess
->
giaddr
.
s_addr
)
{
/* if so check if by us, to stomp on loops. */
if
(
mess
->
giaddr
.
s_addr
==
relay
->
local
.
addr
.
addr4
.
s_addr
)
return
1
;
}
else
{
/* plug in our address */
mess
->
giaddr
.
s_addr
=
relay
->
local
.
addr
.
addr4
.
s_addr
;
}
if
((
mess
->
hops
++
)
>
20
)
return
1
;
for
(;
relay
;
relay
=
relay
->
current
)
{
union
mysockaddr
to
;
to
.
sa
.
sa_family
=
AF_INET
;
to
.
in
.
sin_addr
=
relay
->
server
.
addr
.
addr4
;
to
.
in
.
sin_port
=
htons
(
daemon
->
dhcp_server_port
);
send_from
(
daemon
->
dhcpfd
,
0
,
(
char
*
)
mess
,
sz
,
&
to
,
&
from
,
0
);
if
(
option_bool
(
OPT_LOG_OPTS
))
{
inet_ntop
(
AF_INET
,
&
relay
->
local
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"DHCP relay %s -> %s"
),
daemon
->
addrbuff
,
inet_ntoa
(
relay
->
server
.
addr
.
addr4
));
}
/* Save this for replies */
relay
->
iface_index
=
iface_index
;
}
return
1
;
}
static
struct
dhcp_relay
*
relay_reply4
(
struct
dhcp_packet
*
mess
,
char
*
arrival_interface
)
{
struct
dhcp_relay
*
relay
;
if
(
mess
->
giaddr
.
s_addr
==
0
||
mess
->
op
!=
BOOTREPLY
)
return
NULL
;
for
(
relay
=
daemon
->
relay4
;
relay
;
relay
=
relay
->
next
)
{
if
(
mess
->
giaddr
.
s_addr
==
relay
->
local
.
addr
.
addr4
.
s_addr
)
{
if
(
!
relay
->
interface
||
wildcard_match
(
relay
->
interface
,
arrival_interface
))
return
relay
->
iface_index
!=
0
?
relay
:
NULL
;
}
}
return
NULL
;
}
#endif
src/dhcp6.c
View file @
ff7eea27
...
@@ -20,7 +20,8 @@
...
@@ -20,7 +20,8 @@
struct
iface_param
{
struct
iface_param
{
struct
dhcp_context
*
current
;
struct
dhcp_context
*
current
;
struct
in6_addr
fallback
;
struct
dhcp_relay
*
relay
;
struct
in6_addr
fallback
,
relay_local
;
int
ind
,
addr_match
;
int
ind
,
addr_match
;
};
};
...
@@ -87,6 +88,7 @@ void dhcp6_init(void)
...
@@ -87,6 +88,7 @@ void dhcp6_init(void)
void
dhcp6_packet
(
time_t
now
)
void
dhcp6_packet
(
time_t
now
)
{
{
struct
dhcp_context
*
context
;
struct
dhcp_context
*
context
;
struct
dhcp_relay
*
relay
;
struct
iface_param
parm
;
struct
iface_param
parm
;
struct
cmsghdr
*
cmptr
;
struct
cmsghdr
*
cmptr
;
struct
msghdr
msg
;
struct
msghdr
msg
;
...
@@ -126,56 +128,75 @@ void dhcp6_packet(time_t now)
...
@@ -126,56 +128,75 @@ void dhcp6_packet(time_t now)
if
(
!
indextoname
(
daemon
->
dhcp6fd
,
if_index
,
ifr
.
ifr_name
))
if
(
!
indextoname
(
daemon
->
dhcp6fd
,
if_index
,
ifr
.
ifr_name
))
return
;
return
;
for
(
tmp
=
daemon
->
if_except
;
tmp
;
tmp
=
tmp
->
next
)
if
(
tmp
->
name
&&
wildcard_match
(
tmp
->
name
,
ifr
.
ifr_name
))
return
;
for
(
tmp
=
daemon
->
dhcp_except
;
tmp
;
tmp
=
tmp
->
next
)
if
(
tmp
->
name
&&
wildcard_match
(
tmp
->
name
,
ifr
.
ifr_name
))
return
;
parm
.
current
=
NULL
;
parm
.
ind
=
if_index
;
parm
.
addr_match
=
0
;
memset
(
&
parm
.
fallback
,
0
,
IN6ADDRSZ
);
for
(
context
=
daemon
->
dhcp6
;
context
;
context
=
context
->
next
)
if
((
port
=
relay_reply6
(
&
from
,
sz
,
ifr
.
ifr_name
))
==
0
)
if
(
IN6_IS_ADDR_UNSPECIFIED
(
&
context
->
start6
)
&&
context
->
prefix
==
0
)
{
/* wildcard context for DHCP-stateless only */
parm
.
current
=
context
;
context
->
current
=
NULL
;
}
else
{
/* unlinked contexts are marked by context->current == context */
context
->
current
=
context
;
memset
(
&
context
->
local6
,
0
,
IN6ADDRSZ
);
}
if
(
!
iface_enumerate
(
AF_INET6
,
&
parm
,
complete_context6
))
return
;
if
(
daemon
->
if_names
||
daemon
->
if_addrs
)
{
{
for
(
tmp
=
daemon
->
if_
names
;
tmp
;
tmp
=
tmp
->
next
)
for
(
tmp
=
daemon
->
if_
except
;
tmp
;
tmp
=
tmp
->
next
)
if
(
tmp
->
name
&&
wildcard_match
(
tmp
->
name
,
ifr
.
ifr_name
))
if
(
tmp
->
name
&&
wildcard_match
(
tmp
->
name
,
ifr
.
ifr_name
))
break
;
return
;
for
(
tmp
=
daemon
->
dhcp_except
;
tmp
;
tmp
=
tmp
->
next
)
if
(
tmp
->
name
&&
wildcard_match
(
tmp
->
name
,
ifr
.
ifr_name
))
return
;
parm
.
current
=
NULL
;
parm
.
relay
=
NULL
;
memset
(
&
parm
.
relay_local
,
0
,
IN6ADDRSZ
);
parm
.
ind
=
if_index
;
parm
.
addr_match
=
0
;
memset
(
&
parm
.
fallback
,
0
,
IN6ADDRSZ
);
for
(
context
=
daemon
->
dhcp6
;
context
;
context
=
context
->
next
)
if
(
IN6_IS_ADDR_UNSPECIFIED
(
&
context
->
start6
)
&&
context
->
prefix
==
0
)
{
/* wildcard context for DHCP-stateless only */
parm
.
current
=
context
;
context
->
current
=
NULL
;
}
else
{
/* unlinked contexts are marked by context->current == context */
context
->
current
=
context
;
memset
(
&
context
->
local6
,
0
,
IN6ADDRSZ
);
}
if
(
!
tmp
&&
!
parm
.
addr_match
)
for
(
relay
=
daemon
->
relay6
;
relay
;
relay
=
relay
->
next
)
relay
->
current
=
relay
;
if
(
!
iface_enumerate
(
AF_INET6
,
&
parm
,
complete_context6
))
return
;
return
;
if
(
daemon
->
if_names
||
daemon
->
if_addrs
)
{
for
(
tmp
=
daemon
->
if_names
;
tmp
;
tmp
=
tmp
->
next
)
if
(
tmp
->
name
&&
wildcard_match
(
tmp
->
name
,
ifr
.
ifr_name
))
break
;
if
(
!
tmp
&&
!
parm
.
addr_match
)
return
;
}
if
(
parm
.
relay
)
{
relay_upstream6
(
parm
.
relay
,
sz
,
&
from
.
sin6_addr
,
from
.
sin6_scope_id
);
return
;
}
/* May have configured relay, but not DHCP server */
if
(
!
daemon
->
doing_dhcp6
)
return
;
lease_prune
(
NULL
,
now
);
/* lose any expired leases */
port
=
dhcp6_reply
(
parm
.
current
,
if_index
,
ifr
.
ifr_name
,
&
parm
.
fallback
,
sz
,
IN6_IS_ADDR_MULTICAST
(
&
from
.
sin6_addr
),
now
);
lease_update_file
(
now
);
lease_update_dns
(
0
);
}
}
lease_prune
(
NULL
,
now
);
/* lose any expired leases */
port
=
dhcp6_reply
(
parm
.
current
,
if_index
,
ifr
.
ifr_name
,
&
parm
.
fallback
,
sz
,
IN6_IS_ADDR_MULTICAST
(
&
from
.
sin6_addr
),
now
);
lease_update_file
(
now
);
lease_update_dns
(
0
);
/* The port in the source address of the original request should
/* The port in the source address of the original request should
be correct, but at least once client sends from the server port,
be correct, but at least once client sends from the server port,
so we explicitly send to the client port to a client, and the
so we explicitly send to the client port to a client, and the
...
@@ -194,70 +215,84 @@ static int complete_context6(struct in6_addr *local, int prefix,
...
@@ -194,70 +215,84 @@ static int complete_context6(struct in6_addr *local, int prefix,
unsigned
int
valid
,
void
*
vparam
)
unsigned
int
valid
,
void
*
vparam
)
{
{
struct
dhcp_context
*
context
;
struct
dhcp_context
*
context
;
struct
dhcp_relay
*
relay
;
struct
iface_param
*
param
=
vparam
;
struct
iface_param
*
param
=
vparam
;
struct
iname
*
tmp
;
struct
iname
*
tmp
;
(
void
)
scope
;
/* warning */
(
void
)
scope
;
/* warning */
if
(
if_index
==
param
->
ind
&&
if
(
if_index
==
param
->
ind
)
!
IN6_IS_ADDR_LOOPBACK
(
local
)
&&
!
IN6_IS_ADDR_LINKLOCAL
(
local
)
&&
!
IN6_IS_ADDR_MULTICAST
(
local
))
{
{
/* if we have --listen-address config, see if the
if
(
!
IN6_IS_ADDR_LOOPBACK
(
local
)
&&
arrival interface has a matching address. */
!
IN6_IS_ADDR_LINKLOCAL
(
local
)
&&
for
(
tmp
=
daemon
->
if_addrs
;
tmp
;
tmp
=
tmp
->
next
)
!
IN6_IS_ADDR_MULTICAST
(
local
))
if
(
tmp
->
addr
.
sa
.
sa_family
==
AF_INET6
&&
IN6_ARE_ADDR_EQUAL
(
&
tmp
->
addr
.
in6
.
sin6_addr
,
local
))
param
->
addr_match
=
1
;
/* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only
allocating on remote subnets via relays. This
is used as a default for the DNS server option. */
param
->
fallback
=
*
local
;
for
(
context
=
daemon
->
dhcp6
;
context
;
context
=
context
->
next
)
{
{
if
((
context
->
flags
&
CONTEXT_DHCP
)
&&
/* if we have --listen-address config, see if the
!
(
context
->
flags
&
(
CONTEXT_TEMPLATE
|
CONTEXT_OLD
))
&&
arrival interface has a matching address. */
prefix
==
context
->
prefix
&&
for
(
tmp
=
daemon
->
if_addrs
;
tmp
;
tmp
=
tmp
->
next
)
is_same_net6
(
local
,
&
context
->
start6
,
prefix
)
&&
if
(
tmp
->
addr
.
sa
.
sa_family
==
AF_INET6
&&
is_same_net6
(
local
,
&
context
->
end6
,
prefix
))
IN6_ARE_ADDR_EQUAL
(
&
tmp
->
addr
.
in6
.
sin6_addr
,
local
))
param
->
addr_match
=
1
;
/* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only
allocating on remote subnets via relays. This
is used as a default for the DNS server option. */
param
->
fallback
=
*
local
;
for
(
context
=
daemon
->
dhcp6
;
context
;
context
=
context
->
next
)
{
{
if
((
context
->
flags
&
CONTEXT_DHCP
)
&&
!
(
context
->
flags
&
(
CONTEXT_TEMPLATE
|
CONTEXT_OLD
))
&&
/* link it onto the current chain if we've not seen it before */
prefix
==
context
->
prefix
&&
if
(
context
->
current
==
context
)
is_same_net6
(
local
,
&
context
->
start6
,
prefix
)
&&
is_same_net6
(
local
,
&
context
->
end6
,
prefix
))
{
{
struct
dhcp_context
*
tmp
,
**
up
;
/* use interface values only for contructed contexts */
if
(
!
(
context
->
flags
&
CONTEXT_CONSTRUCTED
))
preferred
=
valid
=
0xffffffff
;
else
if
(
flags
&
IFACE_DEPRECATED
)
preferred
=
0
;
if
(
context
->
flags
&
CONTEXT_DEPRECATE
)
preferred
=
0
;
/* order chain, longest preferred time first */
for
(
up
=
&
param
->
current
,
tmp
=
param
->
current
;
tmp
;
tmp
=
tmp
->
current
)
if
(
tmp
->
preferred
<=
preferred
)
break
;
else
up
=
&
tmp
->
current
;
context
->
current
=
*
up
;
/* link it onto the current chain if we've not seen it before */
*
up
=
context
;
if
(
context
->
current
==
context
)
context
->
local6
=
*
local
;
{
context
->
preferred
=
preferred
;
struct
dhcp_context
*
tmp
,
**
up
;
context
->
valid
=
valid
;
/* use interface values only for contructed contexts */
if
(
!
(
context
->
flags
&
CONTEXT_CONSTRUCTED
))
preferred
=
valid
=
0xffffffff
;
else
if
(
flags
&
IFACE_DEPRECATED
)
preferred
=
0
;
if
(
context
->
flags
&
CONTEXT_DEPRECATE
)
preferred
=
0
;
/* order chain, longest preferred time first */
for
(
up
=
&
param
->
current
,
tmp
=
param
->
current
;
tmp
;
tmp
=
tmp
->
current
)
if
(
tmp
->
preferred
<=
preferred
)
break
;
else
up
=
&
tmp
->
current
;
context
->
current
=
*
up
;
*
up
=
context
;
context
->
local6
=
*
local
;
context
->
preferred
=
preferred
;
context
->
valid
=
valid
;
}
}
}
}
}
}
}
for
(
relay
=
daemon
->
relay6
;
relay
;
relay
=
relay
->
next
)
if
(
IN6_ARE_ADDR_EQUAL
(
local
,
&
relay
->
local
.
addr
.
addr6
)
&&
relay
->
current
==
relay
&&
(
IN6_IS_ADDR_UNSPECIFIED
(
&
param
->
relay_local
)
||
IN6_ARE_ADDR_EQUAL
(
local
,
&
param
->
relay_local
)))
{
relay
->
current
=
param
->
relay
;
param
->
relay
=
relay
;
param
->
relay_local
=
*
local
;
}
}
}
return
1
;
return
1
;
}
}
struct
dhcp_config
*
config_find_by_address6
(
struct
dhcp_config
*
configs
,
struct
in6_addr
*
net
,
int
prefix
,
u64
addr
)
struct
dhcp_config
*
config_find_by_address6
(
struct
dhcp_config
*
configs
,
struct
in6_addr
*
net
,
int
prefix
,
u64
addr
)
...
...
src/dnsmasq.c
View file @
ff7eea27
...
@@ -52,6 +52,7 @@ int main (int argc, char **argv)
...
@@ -52,6 +52,7 @@ int main (int argc, char **argv)
cap_user_data_t
data
=
NULL
;
cap_user_data_t
data
=
NULL
;
#endif
#endif
struct
dhcp_context
*
context
;
struct
dhcp_context
*
context
;
struct
dhcp_relay
*
relay
;
#ifdef LOCALEDIR
#ifdef LOCALEDIR
setlocale
(
LC_ALL
,
""
);
setlocale
(
LC_ALL
,
""
);
...
@@ -166,50 +167,47 @@ int main (int argc, char **argv)
...
@@ -166,50 +167,47 @@ int main (int argc, char **argv)
daemon
->
soa_sn
=
now
;
daemon
->
soa_sn
=
now
;
#endif
#endif
#ifdef HAVE_DHCP
#ifdef HAVE_DHCP6
if
(
daemon
->
dhcp
||
daemon
->
dhcp6
)
if
(
daemon
->
dhcp6
)
{
{
daemon
->
doing_ra
=
option_bool
(
OPT_RA
);
# ifdef HAVE_DHCP6
for
(
context
=
daemon
->
dhcp6
;
context
;
context
=
context
->
next
)
if
(
daemon
->
dhcp6
)
{
{
daemon
->
doing_ra
=
option_bool
(
OPT_RA
);
if
(
context
->
flags
&
CONTEXT_DHCP
)
daemon
->
doing_dhcp6
=
1
;
for
(
context
=
daemon
->
dhcp6
;
context
;
context
=
context
->
next
)
if
(
context
->
flags
&
CONTEXT_RA
)
{
daemon
->
doing_ra
=
1
;
if
(
context
->
flags
&
CONTEXT_DHCP
)
daemon
->
doing_dhcp6
=
1
;
if
(
context
->
flags
&
CONTEXT_RA
)
daemon
->
doing_ra
=
1
;
#ifndef HAVE_LINUX_NETWORK
#ifndef HAVE_LINUX_NETWORK
if
(
context
->
flags
&
CONTEXT_TEMPLATE
)
if
(
context
->
flags
&
CONTEXT_TEMPLATE
)
die
(
_
(
"dhcp-range constructor not available on this platform"
),
NULL
,
EC_BADCONF
);
die
(
_
(
"dhcp-range constructor not available on this platform"
),
NULL
,
EC_BADCONF
);
#endif
#endif
}
}
}
# endif
}
#endif
/* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked
#ifdef HAVE_DHCP
to the lease-script init process. We need to call common_init
/* Note that order matters here, we must call lease_init before
before lease_init to allocate buffers it uses.*/
creating any file descriptors which shouldn't be leaked
to the lease-script init process. We need to call common_init
before lease_init to allocate buffers it uses.*/
if
(
daemon
->
dhcp
||
daemon
->
doing_dhcp6
||
daemon
->
relay4
||
daemon
->
relay6
)
{
dhcp_common_init
();
if
(
daemon
->
dhcp
||
daemon
->
doing_dhcp6
)
if
(
daemon
->
dhcp
||
daemon
->
doing_dhcp6
)
{
lease_init
(
now
);
dhcp_common_init
();
}
lease_init
(
now
);
}
if
(
daemon
->
dhcp
||
daemon
->
relay4
)
dhcp_init
();
if
(
daemon
->
dhcp
)
dhcp_init
();
# ifdef HAVE_DHCP6
# ifdef HAVE_DHCP6
if
(
daemon
->
doing_ra
)
if
(
daemon
->
doing_ra
)
ra_init
(
now
);
ra_init
(
now
);
if
(
daemon
->
doing_dhcp
6
)
if
(
daemon
->
doing_dhcp6
||
daemon
->
relay
6
)
dhcp6_init
();
dhcp6_init
();
# endif
# endif
}
#endif
#endif
...
@@ -239,7 +237,7 @@ int main (int argc, char **argv)
...
@@ -239,7 +237,7 @@ int main (int argc, char **argv)
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
/* after enumerate_interfaces() */
/* after enumerate_interfaces() */
if
(
daemon
->
dhcp
)
if
(
daemon
->
dhcp
||
daemon
->
relay4
)
{
{
bindtodevice
(
daemon
->
dhcpfd
);
bindtodevice
(
daemon
->
dhcpfd
);
if
(
daemon
->
enable_pxe
)
if
(
daemon
->
enable_pxe
)
...
@@ -248,7 +246,7 @@ int main (int argc, char **argv)
...
@@ -248,7 +246,7 @@ int main (int argc, char **argv)
#endif
#endif
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
if
(
daemon
->
doing_dhcp6
)
if
(
daemon
->
doing_dhcp6
||
daemon
->
relay6
)
bindtodevice
(
daemon
->
dhcp6fd
);
bindtodevice
(
daemon
->
dhcp6fd
);
#endif
#endif
}
}
...
@@ -257,7 +255,7 @@ int main (int argc, char **argv)
...
@@ -257,7 +255,7 @@ int main (int argc, char **argv)
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
/* after enumerate_interfaces() */
/* after enumerate_interfaces() */
if
(
daemon
->
doing_dhcp6
||
daemon
->
doing_ra
)
if
(
daemon
->
doing_dhcp6
||
daemon
->
relay6
||
daemon
->
doing_ra
)
join_multicast
(
1
);
join_multicast
(
1
);
#endif
#endif
...
@@ -641,10 +639,16 @@ int main (int argc, char **argv)
...
@@ -641,10 +639,16 @@ int main (int argc, char **argv)
for
(
context
=
daemon
->
dhcp
;
context
;
context
=
context
->
next
)
for
(
context
=
daemon
->
dhcp
;
context
;
context
=
context
->
next
)
log_context
(
AF_INET
,
context
);
log_context
(
AF_INET
,
context
);
for
(
relay
=
daemon
->
relay4
;
relay
;
relay
=
relay
->
next
)
log_relay
(
AF_INET
,
relay
);
# ifdef HAVE_DHCP6
# ifdef HAVE_DHCP6
for
(
context
=
daemon
->
dhcp6
;
context
;
context
=
context
->
next
)
for
(
context
=
daemon
->
dhcp6
;
context
;
context
=
context
->
next
)
log_context
(
AF_INET6
,
context
);
log_context
(
AF_INET6
,
context
);
for
(
relay
=
daemon
->
relay6
;
relay
;
relay
=
relay
->
next
)
log_relay
(
AF_INET6
,
relay
);
if
(
daemon
->
doing_dhcp6
||
daemon
->
doing_ra
)
if
(
daemon
->
doing_dhcp6
||
daemon
->
doing_ra
)
dhcp_construct_contexts
(
now
);
dhcp_construct_contexts
(
now
);
...
@@ -749,7 +753,7 @@ int main (int argc, char **argv)
...
@@ -749,7 +753,7 @@ int main (int argc, char **argv)
#endif
#endif
#ifdef HAVE_DHCP
#ifdef HAVE_DHCP
if
(
daemon
->
dhcp
)
if
(
daemon
->
dhcp
||
daemon
->
relay4
)
{
{
FD_SET
(
daemon
->
dhcpfd
,
&
rset
);
FD_SET
(
daemon
->
dhcpfd
,
&
rset
);
bump_maxfd
(
daemon
->
dhcpfd
,
&
maxfd
);
bump_maxfd
(
daemon
->
dhcpfd
,
&
maxfd
);
...
@@ -762,7 +766,7 @@ int main (int argc, char **argv)
...
@@ -762,7 +766,7 @@ int main (int argc, char **argv)
#endif
#endif
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
if
(
daemon
->
doing_dhcp6
)
if
(
daemon
->
doing_dhcp6
||
daemon
->
relay6
)
{
{
FD_SET
(
daemon
->
dhcp6fd
,
&
rset
);
FD_SET
(
daemon
->
dhcp6fd
,
&
rset
);
bump_maxfd
(
daemon
->
dhcp6fd
,
&
maxfd
);
bump_maxfd
(
daemon
->
dhcp6fd
,
&
maxfd
);
...
@@ -874,7 +878,7 @@ int main (int argc, char **argv)
...
@@ -874,7 +878,7 @@ int main (int argc, char **argv)
#endif
#endif
#ifdef HAVE_DHCP
#ifdef HAVE_DHCP
if
(
daemon
->
dhcp
)
if
(
daemon
->
dhcp
||
daemon
->
relay4
)
{
{
if
(
FD_ISSET
(
daemon
->
dhcpfd
,
&
rset
))
if
(
FD_ISSET
(
daemon
->
dhcpfd
,
&
rset
))
dhcp_packet
(
now
,
0
);
dhcp_packet
(
now
,
0
);
...
@@ -883,7 +887,7 @@ int main (int argc, char **argv)
...
@@ -883,7 +887,7 @@ int main (int argc, char **argv)
}
}
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
if
(
daemon
->
doing_dhcp6
&&
FD_ISSET
(
daemon
->
dhcp6fd
,
&
rset
))
if
(
(
daemon
->
doing_dhcp6
||
daemon
->
relay6
)
&&
FD_ISSET
(
daemon
->
dhcp6fd
,
&
rset
))
dhcp6_packet
(
now
);
dhcp6_packet
(
now
);
if
(
daemon
->
doing_ra
&&
FD_ISSET
(
daemon
->
icmp6fd
,
&
rset
))
if
(
daemon
->
doing_ra
&&
FD_ISSET
(
daemon
->
icmp6fd
,
&
rset
))
...
...
src/dnsmasq.h
View file @
ff7eea27
...
@@ -775,6 +775,12 @@ struct tftp_prefix {
...
@@ -775,6 +775,12 @@ struct tftp_prefix {
struct
tftp_prefix
*
next
;
struct
tftp_prefix
*
next
;
};
};
struct
dhcp_relay
{
struct
all_addr
local
,
server
;
char
*
interface
;
/* Allowable interface for replies from server, and dest for IPv6 multicast */
int
iface_index
;
/* working - interface in which requests arrived, for return */
struct
dhcp_relay
*
current
,
*
next
;
};
extern
struct
daemon
{
extern
struct
daemon
{
/* datastuctures representing the command-line and
/* datastuctures representing the command-line and
...
@@ -824,6 +830,7 @@ extern struct daemon {
...
@@ -824,6 +830,7 @@ extern struct daemon {
struct
pxe_service
*
pxe_services
;
struct
pxe_service
*
pxe_services
;
struct
tag_if
*
tag_if
;
struct
tag_if
*
tag_if
;
struct
addr_list
*
override_relays
;
struct
addr_list
*
override_relays
;
struct
dhcp_relay
*
relay4
,
*
relay6
;
int
override
;
int
override
;
int
enable_pxe
;
int
enable_pxe
;
int
doing_ra
,
doing_dhcp6
;
int
doing_ra
,
doing_dhcp6
;
...
@@ -1217,6 +1224,9 @@ void dhcp_construct_contexts(time_t now);
...
@@ -1217,6 +1224,9 @@ void dhcp_construct_contexts(time_t now);
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
unsigned
short
dhcp6_reply
(
struct
dhcp_context
*
context
,
int
interface
,
char
*
iface_name
,
unsigned
short
dhcp6_reply
(
struct
dhcp_context
*
context
,
int
interface
,
char
*
iface_name
,
struct
in6_addr
*
fallback
,
size_t
sz
,
int
is_multicast
,
time_t
now
);
struct
in6_addr
*
fallback
,
size_t
sz
,
int
is_multicast
,
time_t
now
);
void
relay_upstream6
(
struct
dhcp_relay
*
relay
,
ssize_t
sz
,
struct
in6_addr
*
peer_address
,
u32
scope_id
);
unsigned
short
relay_reply6
(
struct
sockaddr_in6
*
peer
,
ssize_t
sz
,
char
*
arrival_interface
);
#endif
#endif
/* dhcp-common.c */
/* dhcp-common.c */
...
@@ -1243,6 +1253,7 @@ void bindtodevice(int fd);
...
@@ -1243,6 +1253,7 @@ void bindtodevice(int fd);
void
display_opts6
(
void
);
void
display_opts6
(
void
);
# endif
# endif
void
log_context
(
int
family
,
struct
dhcp_context
*
context
);
void
log_context
(
int
family
,
struct
dhcp_context
*
context
);
void
log_relay
(
int
family
,
struct
dhcp_relay
*
relay
);
#endif
#endif
/* outpacket.c */
/* outpacket.c */
...
...
src/netlink.c
View file @
ff7eea27
...
@@ -402,18 +402,18 @@ static int nl_async(struct nlmsghdr *h)
...
@@ -402,18 +402,18 @@ static int nl_async(struct nlmsghdr *h)
static
void
nl_newaddress
(
time_t
now
)
static
void
nl_newaddress
(
time_t
now
)
{
{
if
(
option_bool
(
OPT_CLEVERBIND
)
||
daemon
->
doing_dhcp6
||
daemon
->
doing_ra
)
if
(
option_bool
(
OPT_CLEVERBIND
)
||
daemon
->
doing_dhcp6
||
daemon
->
relay6
||
daemon
->
doing_ra
)
enumerate_interfaces
(
0
);
enumerate_interfaces
(
0
);
if
(
option_bool
(
OPT_CLEVERBIND
))
if
(
option_bool
(
OPT_CLEVERBIND
))
create_bound_listeners
(
0
);
create_bound_listeners
(
0
);
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
if
(
daemon
->
doing_dhcp6
||
daemon
->
relay6
||
daemon
->
doing_ra
)
join_multicast
(
0
);
if
(
daemon
->
doing_dhcp6
||
daemon
->
doing_ra
)
if
(
daemon
->
doing_dhcp6
||
daemon
->
doing_ra
)
{
dhcp_construct_contexts
(
now
);
join_multicast
(
0
);
dhcp_construct_contexts
(
now
);
}
if
(
daemon
->
doing_dhcp6
)
if
(
daemon
->
doing_dhcp6
)
lease_find_interfaces
(
now
);
lease_find_interfaces
(
now
);
...
...
src/network.c
View file @
ff7eea27
...
@@ -851,7 +851,7 @@ void join_multicast(int dienow)
...
@@ -851,7 +851,7 @@ void join_multicast(int dienow)
inet_pton
(
AF_INET6
,
ALL_RELAY_AGENTS_AND_SERVERS
,
&
mreq
.
ipv6mr_multiaddr
);
inet_pton
(
AF_INET6
,
ALL_RELAY_AGENTS_AND_SERVERS
,
&
mreq
.
ipv6mr_multiaddr
);
if
(
daemon
->
doing_dhcp6
&&
if
(
(
daemon
->
doing_dhcp6
||
daemon
->
relay6
)
&&
setsockopt
(
daemon
->
dhcp6fd
,
IPPROTO_IPV6
,
IPV6_JOIN_GROUP
,
&
mreq
,
sizeof
(
mreq
))
==
-
1
)
setsockopt
(
daemon
->
dhcp6fd
,
IPPROTO_IPV6
,
IPV6_JOIN_GROUP
,
&
mreq
,
sizeof
(
mreq
))
==
-
1
)
err
=
1
;
err
=
1
;
...
...
src/option.c
View file @
ff7eea27
...
@@ -133,6 +133,7 @@ struct myoption {
...
@@ -133,6 +133,7 @@ struct myoption {
#define LOPT_PREF_CLSS 321
#define LOPT_PREF_CLSS 321
#endif
#endif
#define LOPT_FAST_RA 322
#define LOPT_FAST_RA 322
#define LOPT_RELAY 323
#ifdef HAVE_GETOPT_LONG
#ifdef HAVE_GETOPT_LONG
static
const
struct
option
opts
[]
=
static
const
struct
option
opts
[]
=
...
@@ -271,6 +272,7 @@ static const struct myoption opts[] =
...
@@ -271,6 +272,7 @@ static const struct myoption opts[] =
{
"dhcp-prefix-class"
,
1
,
0
,
LOPT_PREF_CLSS
},
{
"dhcp-prefix-class"
,
1
,
0
,
LOPT_PREF_CLSS
},
#endif
#endif
{
"force-fast-ra"
,
0
,
0
,
LOPT_FAST_RA
},
{
"force-fast-ra"
,
0
,
0
,
LOPT_FAST_RA
},
{
"dhcp-relay"
,
1
,
0
,
LOPT_RELAY
},
{
NULL
,
0
,
0
,
0
}
{
NULL
,
0
,
0
,
0
}
};
};
...
@@ -389,6 +391,7 @@ static struct {
...
@@ -389,6 +391,7 @@ static struct {
{
LOPT_DHCP_FQDN
,
OPT_DHCP_FQDN
,
NULL
,
gettext_noop
(
"Use only fully qualified domain names for DHCP clients."
),
NULL
},
{
LOPT_DHCP_FQDN
,
OPT_DHCP_FQDN
,
NULL
,
gettext_noop
(
"Use only fully qualified domain names for DHCP clients."
),
NULL
},
{
LOPT_GEN_NAMES
,
ARG_DUP
,
"[=tag:<tag>]"
,
gettext_noop
(
"Generate hostnames based on MAC address for nameless clients."
),
NULL
},
{
LOPT_GEN_NAMES
,
ARG_DUP
,
"[=tag:<tag>]"
,
gettext_noop
(
"Generate hostnames based on MAC address for nameless clients."
),
NULL
},
{
LOPT_PROXY
,
ARG_DUP
,
"[=<ipaddr>]..."
,
gettext_noop
(
"Use these DHCP relays as full proxies."
),
NULL
},
{
LOPT_PROXY
,
ARG_DUP
,
"[=<ipaddr>]..."
,
gettext_noop
(
"Use these DHCP relays as full proxies."
),
NULL
},
{
LOPT_RELAY
,
ARG_DUP
,
"<local-addr>,<server>[,<interface>]"
,
gettext_noop
(
"Relay DHCP requests to a remote server"
),
NULL
},
{
LOPT_CNAME
,
ARG_DUP
,
"<alias>,<target>"
,
gettext_noop
(
"Specify alias name for LOCAL DNS name."
),
NULL
},
{
LOPT_CNAME
,
ARG_DUP
,
"<alias>,<target>"
,
gettext_noop
(
"Specify alias name for LOCAL DNS name."
),
NULL
},
{
LOPT_PXE_PROMT
,
ARG_DUP
,
"<prompt>,[<timeout>]"
,
gettext_noop
(
"Prompt to send to PXE clients."
),
NULL
},
{
LOPT_PXE_PROMT
,
ARG_DUP
,
"<prompt>,[<timeout>]"
,
gettext_noop
(
"Prompt to send to PXE clients."
),
NULL
},
{
LOPT_PXE_SERV
,
ARG_DUP
,
"<service>"
,
gettext_noop
(
"Boot service for PXE menu."
),
NULL
},
{
LOPT_PXE_SERV
,
ARG_DUP
,
"<service>"
,
gettext_noop
(
"Boot service for PXE menu."
),
NULL
},
...
@@ -3178,6 +3181,31 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
...
@@ -3178,6 +3181,31 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
arg
=
comma
;
arg
=
comma
;
}
}
break
;
break
;
case
LOPT_RELAY
:
/* --dhcp-relay */
{
struct
dhcp_relay
*
new
=
opt_malloc
(
sizeof
(
struct
dhcp_relay
));
comma
=
split
(
arg
);
new
->
interface
=
opt_string_alloc
(
split
(
comma
));
new
->
iface_index
=
0
;
if
(
inet_pton
(
AF_INET
,
arg
,
&
new
->
local
)
&&
inet_pton
(
AF_INET
,
comma
,
&
new
->
server
))
{
new
->
next
=
daemon
->
relay4
;
daemon
->
relay4
=
new
;
}
#ifdef HAVE_DHCP6
else
if
(
inet_pton
(
AF_INET6
,
arg
,
&
new
->
local
)
&&
inet_pton
(
AF_INET6
,
comma
,
&
new
->
server
))
{
new
->
next
=
daemon
->
relay6
;
daemon
->
relay6
=
new
;
}
#endif
else
ret_err
(
_
(
"Bad dhcp-relay"
));
break
;
}
#endif
#endif
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
...
...
src/outpacket.c
View file @
ff7eea27
...
@@ -70,9 +70,9 @@ void *put_opt6(void *data, size_t len)
...
@@ -70,9 +70,9 @@ void *put_opt6(void *data, size_t len)
{
{
void
*
p
;
void
*
p
;
if
((
p
=
expand
(
len
)))
if
((
p
=
expand
(
len
))
&&
data
)
memcpy
(
p
,
data
,
len
);
memcpy
(
p
,
data
,
len
);
return
p
;
return
p
;
}
}
...
...
src/rfc3315.c
View file @
ff7eea27
...
@@ -155,7 +155,8 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **
...
@@ -155,7 +155,8 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **
return
0
;
return
0
;
/* copy header stuff into reply message and set type to reply */
/* copy header stuff into reply message and set type to reply */
outmsgtypep
=
put_opt6
(
inbuff
,
34
);
if
(
!
(
outmsgtypep
=
put_opt6
(
inbuff
,
34
)))
return
0
;
*
outmsgtypep
=
DHCP6RELAYREPL
;
*
outmsgtypep
=
DHCP6RELAYREPL
;
/* look for relay options and set tags if found. */
/* look for relay options and set tags if found. */
...
@@ -252,7 +253,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
...
@@ -252,7 +253,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
state
.
tags
=
&
v6_id
;
state
.
tags
=
&
v6_id
;
/* copy over transaction-id, and save pointer to message type */
/* copy over transaction-id, and save pointer to message type */
outmsgtypep
=
put_opt6
(
inbuff
,
4
);
if
(
!
(
outmsgtypep
=
put_opt6
(
inbuff
,
4
)))
return
0
;
start_opts
=
save_counter
(
-
1
);
start_opts
=
save_counter
(
-
1
);
state
.
xid
=
outmsgtypep
[
3
]
|
outmsgtypep
[
2
]
<<
8
|
outmsgtypep
[
1
]
<<
16
;
state
.
xid
=
outmsgtypep
[
3
]
|
outmsgtypep
[
2
]
<<
8
|
outmsgtypep
[
1
]
<<
16
;
...
@@ -1912,4 +1914,118 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
...
@@ -1912,4 +1914,118 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
return
ret
;
return
ret
;
}
}
void
relay_upstream6
(
struct
dhcp_relay
*
relay
,
ssize_t
sz
,
struct
in6_addr
*
peer_address
,
u32
scope_id
)
{
/* ->local is same value for all relays on ->current chain */
struct
all_addr
from
;
unsigned
char
*
header
;
unsigned
char
*
inbuff
=
daemon
->
dhcp_packet
.
iov_base
;
int
msg_type
=
*
inbuff
;
int
hopcount
;
struct
in6_addr
multicast
;
inet_pton
(
AF_INET6
,
ALL_SERVERS
,
&
multicast
);
/* source address == relay address */
from
.
addr
.
addr6
=
relay
->
local
.
addr
.
addr6
;
/* Get hop count from nested relayed message */
if
(
msg_type
==
DHCP6RELAYFORW
)
hopcount
=
*
((
unsigned
char
*
)
inbuff
+
1
)
+
1
;
else
hopcount
=
0
;
/* RFC 3315 HOP_COUNT_LIMIT */
if
(
hopcount
>
32
)
return
;
save_counter
(
0
);
if
((
header
=
put_opt6
(
NULL
,
34
)))
{
int
o
;
header
[
0
]
=
DHCP6RELAYFORW
;
header
[
1
]
=
hopcount
;
memcpy
(
&
header
[
2
],
&
relay
->
local
.
addr
.
addr6
,
IN6ADDRSZ
);
memcpy
(
&
header
[
18
],
peer_address
,
IN6ADDRSZ
);
o
=
new_opt6
(
OPTION6_RELAY_MSG
);
put_opt6
(
inbuff
,
sz
);
end_opt6
(
o
);
for
(;
relay
;
relay
=
relay
->
current
)
{
union
mysockaddr
to
;
to
.
sa
.
sa_family
=
AF_INET6
;
to
.
in6
.
sin6_addr
=
relay
->
server
.
addr
.
addr6
;
to
.
in6
.
sin6_port
=
htons
(
DHCPV6_SERVER_PORT
);
to
.
in6
.
sin6_flowinfo
=
0
;
to
.
in6
.
sin6_scope_id
=
0
;
if
(
IN6_ARE_ADDR_EQUAL
(
&
relay
->
server
.
addr
.
addr6
,
&
multicast
))
{
int
multicast_iface
;
if
(
!
relay
->
interface
||
strchr
(
relay
->
interface
,
'*'
)
||
(
multicast_iface
=
if_nametoindex
(
relay
->
interface
))
==
0
||
setsockopt
(
daemon
->
dhcp6fd
,
IPPROTO_IPV6
,
IPV6_MULTICAST_IF
,
&
multicast_iface
,
sizeof
(
multicast_iface
))
==
-
1
)
my_syslog
(
MS_DHCP
|
LOG_ERR
,
_
(
"Cannot multicast to DHCPv6 server without correct interface"
));
}
send_from
(
daemon
->
dhcp6fd
,
0
,
daemon
->
outpacket
.
iov_base
,
save_counter
(
0
),
&
to
,
&
from
,
0
);
if
(
option_bool
(
OPT_LOG_OPTS
))
{
inet_ntop
(
AF_INET6
,
&
relay
->
local
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
inet_ntop
(
AF_INET6
,
&
relay
->
server
,
daemon
->
namebuff
,
ADDRSTRLEN
);
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"DHCP relay %s -> %s"
),
daemon
->
addrbuff
,
daemon
->
namebuff
);
}
/* Save this for replies */
relay
->
iface_index
=
scope_id
;
}
}
}
unsigned
short
relay_reply6
(
struct
sockaddr_in6
*
peer
,
ssize_t
sz
,
char
*
arrival_interface
)
{
struct
dhcp_relay
*
relay
;
struct
in6_addr
link
;
unsigned
char
*
inbuff
=
daemon
->
dhcp_packet
.
iov_base
;
/* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
if
(
sz
<
38
||
*
inbuff
!=
DHCP6RELAYREPL
)
return
0
;
memcpy
(
&
link
,
&
inbuff
[
2
],
IN6ADDRSZ
);
for
(
relay
=
daemon
->
relay6
;
relay
;
relay
=
relay
->
next
)
if
(
IN6_ARE_ADDR_EQUAL
(
&
link
,
&
relay
->
local
.
addr
.
addr6
)
&&
(
!
relay
->
interface
||
wildcard_match
(
relay
->
interface
,
arrival_interface
)))
break
;
save_counter
(
0
);
if
(
relay
)
{
void
*
opt
,
*
opts
=
inbuff
+
34
;
void
*
end
=
inbuff
+
sz
;
for
(
opt
=
opts
;
opt
;
opt
=
opt6_next
(
opt
,
end
))
if
(
opt6_type
(
opt
)
==
OPTION6_RELAY_MSG
&&
opt6_len
(
opt
)
>
0
)
{
int
encap_type
=
*
((
unsigned
char
*
)
opt6_ptr
(
opt
,
0
));
put_opt6
(
opt6_ptr
(
opt
,
0
),
opt6_len
(
opt
));
memcpy
(
&
peer
->
sin6_addr
,
&
inbuff
[
18
],
IN6ADDRSZ
);
peer
->
sin6_scope_id
=
relay
->
iface_index
;
return
encap_type
==
DHCP6RELAYREPL
?
DHCPV6_SERVER_PORT
:
DHCPV6_CLIENT_PORT
;
}
}
return
0
;
}
#endif
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment