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
a6ebfacf
Commit
a6ebfacf
authored
Mar 06, 2013
by
Simon Kelley
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Massive refactor of stateful DHCPv6. Lease multiple prefixes per client.
parent
c7961075
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
693 additions
and
618 deletions
+693
-618
src/dhcp6.c
src/dhcp6.c
+8
-36
src/dnsmasq.h
src/dnsmasq.h
+13
-6
src/lease.c
src/lease.c
+28
-17
src/rfc3315.c
src/rfc3315.c
+644
-559
No files found.
src/dhcp6.c
View file @
a6ebfacf
...
...
@@ -265,8 +265,8 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
return
NULL
;
}
int
address6_allocate
(
struct
dhcp_context
*
context
,
unsigned
char
*
clid
,
int
clid_len
,
int
serial
,
struct
dhcp_netid
*
netids
,
struct
in6_addr
*
ans
)
struct
dhcp_context
*
address6_allocate
(
struct
dhcp_context
*
context
,
unsigned
char
*
clid
,
int
clid_len
,
int
iaid
,
struct
dhcp_netid
*
netids
,
struct
in6_addr
*
ans
)
{
/* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration.
...
...
@@ -283,12 +283,12 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
/* hash hwaddr: use the SDBM hashing algorithm. This works
for MAC addresses, let's see how it manages with client-ids! */
for
(
j
=
0
,
i
=
0
;
i
<
clid_len
;
i
++
)
for
(
j
=
iaid
,
i
=
0
;
i
<
clid_len
;
i
++
)
j
+=
clid
[
i
]
+
(
j
<<
6
)
+
(
j
<<
16
)
-
j
;
for
(
pass
=
0
;
pass
<=
1
;
pass
++
)
for
(
c
=
context
;
c
;
c
=
c
->
current
)
if
(
c
->
flags
&
(
CONTEXT_DEPRECATE
|
CONTEXT_STATIC
|
CONTEXT_RA_STATELESS
))
if
(
c
->
flags
&
(
CONTEXT_DEPRECATE
|
CONTEXT_STATIC
|
CONTEXT_RA_STATELESS
|
CONTEXT_USED
))
continue
;
else
if
(
!
match_netid
(
c
->
filter
,
netids
,
pass
))
continue
;
...
...
@@ -296,9 +296,9 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
{
if
(
option_bool
(
OPT_CONSEC_ADDR
))
/* seed is largest extant lease addr in this context */
start
=
lease_find_max_addr6
(
c
)
+
serial
;
start
=
lease_find_max_addr6
(
c
);
else
start
=
addr6part
(
&
c
->
start6
)
+
((
j
+
c
->
addr_epoch
+
serial
)
%
(
1
+
addr6part
(
&
c
->
end6
)
-
addr6part
(
&
c
->
start6
)));
start
=
addr6part
(
&
c
->
start6
)
+
((
j
+
c
->
addr_epoch
)
%
(
1
+
addr6part
(
&
c
->
end6
)
-
addr6part
(
&
c
->
start6
)));
/* iterate until we find a free address. */
addr
=
start
;
...
...
@@ -315,7 +315,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
{
*
ans
=
c
->
start6
;
setaddr6part
(
ans
,
addr
);
return
1
;
return
c
;
}
addr
++
;
...
...
@@ -369,34 +369,6 @@ struct dhcp_context *address6_valid(struct dhcp_context *context,
return
NULL
;
}
struct
dhcp_context
*
narrow_context6
(
struct
dhcp_context
*
context
,
struct
in6_addr
*
taddr
,
struct
dhcp_netid
*
netids
)
{
/* We start of with a set of possible contexts, all on the current physical interface.
These are chained on ->current.
Here we have an address, and return the actual context correponding to that
address. Note that none may fit, if the address came a dhcp-host and is outside
any dhcp-range. In that case we return a static range if possible, or failing that,
any context on the correct subnet. (If there's more than one, this is a dodgy
configuration: maybe there should be a warning.) */
struct
dhcp_context
*
tmp
;
if
(
!
(
tmp
=
address6_available
(
context
,
taddr
,
netids
))
&&
!
(
tmp
=
address6_valid
(
context
,
taddr
,
netids
)))
for
(
tmp
=
context
;
tmp
;
tmp
=
tmp
->
current
)
if
(
match_netid
(
tmp
->
filter
,
netids
,
1
)
&&
is_same_net6
(
taddr
,
&
tmp
->
start6
,
tmp
->
prefix
))
break
;
/* Only one context allowed now */
if
(
tmp
)
tmp
->
current
=
NULL
;
return
tmp
;
}
static
int
is_config_in_context6
(
struct
dhcp_context
*
context
,
struct
dhcp_config
*
config
)
{
/* expand wildcard on contructed contexts */
...
...
src/dnsmasq.h
View file @
a6ebfacf
...
...
@@ -681,6 +681,14 @@ struct cond_domain {
struct
cond_domain
*
next
;
};
#ifdef OPTION6_PREFIX_CLASS
struct
prefix_class
{
int
class
;
struct
dhcp_netid
netid
;
struct
prefix_class
*
next
;
};
#endif
struct
dhcp_context
{
unsigned
int
lease_time
,
addr_epoch
;
struct
in_addr
netmask
,
broadcast
;
...
...
@@ -714,6 +722,7 @@ struct dhcp_context {
#define CONTEXT_GC 4096
#define CONTEXT_RA 8192
#define CONTEXT_WILDCARD 16384
#define CONTEXT_USED 32768
struct
ping_result
{
struct
in_addr
addr
;
...
...
@@ -1055,7 +1064,8 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr);
struct
dhcp_lease
*
lease6_allocate
(
struct
in6_addr
*
addrp
,
int
lease_type
);
struct
dhcp_lease
*
lease6_find
(
unsigned
char
*
clid
,
int
clid_len
,
int
lease_type
,
int
iaid
,
struct
in6_addr
*
addr
);
void
lease6_filter
(
int
lease_type
,
int
iaid
,
struct
dhcp_context
*
context
);
void
lease6_reset
(
void
);
struct
dhcp_lease
*
lease6_find_by_client
(
struct
dhcp_lease
*
first
,
int
lease_type
,
unsigned
char
*
clid
,
int
clid_len
,
int
iaid
);
struct
dhcp_lease
*
lease6_find_by_addr
(
struct
in6_addr
*
net
,
int
prefix
,
u64
addr
);
u64
lease_find_max_addr6
(
struct
dhcp_context
*
context
);
void
lease_ping_reply
(
struct
in6_addr
*
sender
,
unsigned
char
*
packet
,
char
*
interface
);
...
...
@@ -1160,8 +1170,8 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
#ifdef HAVE_DHCP6
void
dhcp6_init
(
void
);
void
dhcp6_packet
(
time_t
now
);
int
address6_allocate
(
struct
dhcp_context
*
context
,
unsigned
char
*
clid
,
int
clid_len
,
int
serial
,
struct
dhcp_netid
*
netids
,
struct
in6_addr
*
ans
);
struct
dhcp_context
*
address6_allocate
(
struct
dhcp_context
*
context
,
unsigned
char
*
clid
,
int
clid_len
,
int
iaid
,
struct
dhcp_netid
*
netids
,
struct
in6_addr
*
ans
);
int
is_addr_in_context6
(
struct
dhcp_context
*
context
,
struct
in6_addr
*
addr
);
struct
dhcp_context
*
address6_available
(
struct
dhcp_context
*
context
,
struct
in6_addr
*
taddr
,
...
...
@@ -1169,9 +1179,6 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
struct
dhcp_context
*
address6_valid
(
struct
dhcp_context
*
context
,
struct
in6_addr
*
taddr
,
struct
dhcp_netid
*
netids
);
struct
dhcp_context
*
narrow_context6
(
struct
dhcp_context
*
context
,
struct
in6_addr
*
taddr
,
struct
dhcp_netid
*
netids
);
struct
dhcp_config
*
find_config6
(
struct
dhcp_config
*
configs
,
struct
dhcp_context
*
context
,
unsigned
char
*
duid
,
int
duid_len
,
...
...
src/lease.c
View file @
a6ebfacf
...
...
@@ -555,8 +555,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
}
#ifdef HAVE_DHCP6
/* addr or clid may be NULL for "don't care, both NULL resets "USED" flags both
set activates USED check */
/* find address for {CLID, IAID, address} */
struct
dhcp_lease
*
lease6_find
(
unsigned
char
*
clid
,
int
clid_len
,
int
lease_type
,
int
iaid
,
struct
in6_addr
*
addr
)
{
...
...
@@ -567,40 +566,52 @@ struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
if
(
!
(
lease
->
flags
&
lease_type
)
||
lease
->
hwaddr_type
!=
iaid
)
continue
;
if
(
clid
&&
addr
&&
(
lease
->
flags
&
LEASE_USED
)
)
if
(
memcmp
(
lease
->
hwaddr
,
addr
,
IN6ADDRSZ
)
!=
0
)
continue
;
if
(
addr
&&
memcmp
(
lease
->
hwaddr
,
addr
,
IN6ADDRSZ
)
!=
0
)
continue
;
if
(
clid
&&
(
clid_len
!=
lease
->
clid_len
||
if
((
clid_len
!=
lease
->
clid_len
||
memcmp
(
clid
,
lease
->
clid
,
clid_len
)
!=
0
))
continue
;
lease
->
flags
|=
LEASE_USED
;
return
lease
;
}
return
NULL
;
}
void
lease6_filter
(
int
lease_type
,
int
iaid
,
struct
dhcp_context
*
context
)
/* reset "USED flags */
void
lease6_reset
(
void
)
{
struct
dhcp_lease
*
lease
;
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
{
/* reset "USED flag */
lease
->
flags
&=
~
LEASE_USED
;
}
/* enumerate all leases belonging to {CLID, IAID} */
struct
dhcp_lease
*
lease6_find_by_client
(
struct
dhcp_lease
*
first
,
int
lease_type
,
unsigned
char
*
clid
,
int
clid_len
,
int
iaid
)
{
struct
dhcp_lease
*
lease
;
if
(
!
first
)
first
=
leases
;
for
(
lease
=
first
;
lease
;
lease
=
lease
->
next
)
{
if
(
lease
->
flags
&
LEASE_USED
)
continue
;
if
(
!
(
lease
->
flags
&
lease_type
)
||
lease
->
hwaddr_type
!=
iaid
)
continue
;
/* leases on the wrong interface get filtered out here */
if
(
!
is_addr_in_context6
(
context
,
(
struct
in6_addr
*
)
&
lease
->
hwaddr
))
lease
->
flags
|=
LEASE_USED
;
if
((
clid_len
!=
lease
->
clid_len
||
memcmp
(
clid
,
lease
->
clid
,
clid_len
)
!=
0
))
continue
;
return
lease
;
}
return
NULL
;
}
struct
dhcp_lease
*
lease6_find_by_addr
(
struct
in6_addr
*
net
,
int
prefix
,
u64
addr
)
...
...
src/rfc3315.c
View file @
a6ebfacf
...
...
@@ -19,16 +19,37 @@
#ifdef HAVE_DHCP6
struct
state
{
unsigned
char
*
clid
;
int
clid_len
,
iaid
,
ia_type
,
interface
,
hostname_auth
;
char
*
client_hostname
,
*
hostname
,
*
domain
,
*
send_domain
;
struct
dhcp_context
*
context
;
struct
in6_addr
*
link_address
;
unsigned
int
xid
,
fqdn_flags
;
char
*
iface_name
;
void
*
packet_options
,
*
end
;
struct
dhcp_netid
*
tags
,
*
context_tags
;
};
static
int
dhcp6_maybe_relay
(
struct
in6_addr
*
link_address
,
struct
dhcp_netid
**
relay_tagsp
,
struct
dhcp_context
*
context
,
int
interface
,
char
*
iface_name
,
struct
in6_addr
*
fallback
,
void
*
inbuff
,
size_t
sz
,
int
is_unicast
,
time_t
now
);
static
int
dhcp6_no_relay
(
int
msg_type
,
struct
in6_addr
*
link_address
,
struct
dhcp_netid
*
tags
,
struct
dhcp_context
*
context
,
int
interface
,
char
*
iface_name
,
struct
in6_addr
*
fallback
,
void
*
inbuff
,
size_t
sz
,
int
is_unicast
,
time_t
now
);
static
void
log6_opts
(
int
nest
,
unsigned
int
xid
,
void
*
start_opts
,
void
*
end_opts
);
static
void
log6_packet
(
char
*
type
,
unsigned
char
*
clid
,
int
clid_len
,
struct
in6_addr
*
addr
,
int
xid
,
char
*
iface
,
char
*
string
);
static
void
log6_packet
(
struct
state
*
state
,
char
*
type
,
struct
in6_addr
*
addr
,
char
*
string
);
static
void
*
opt6_find
(
void
*
opts
,
void
*
end
,
unsigned
int
search
,
unsigned
int
minsize
);
static
void
*
opt6_next
(
void
*
opts
,
void
*
end
);
static
unsigned
int
opt6_uint
(
unsigned
char
*
opt
,
int
offset
,
int
size
);
static
void
get_context_tag
(
struct
state
*
state
,
struct
dhcp_context
*
context
);
static
void
*
check_ia
(
struct
state
*
state
,
void
*
opt
,
void
**
endp
);
static
int
build_ia
(
struct
state
*
state
,
int
*
t1cntr
);
static
void
end_ia
(
int
t1cntr
,
unsigned
int
min_time
,
int
do_fuzz
);
static
void
add_address
(
struct
state
*
state
,
struct
dhcp_context
*
context
,
unsigned
int
lease_time
,
unsigned
int
requested_time
,
unsigned
int
*
min_time
,
struct
in6_addr
*
addr
,
int
update_lease
,
time_t
now
);
static
void
update_leases
(
struct
state
*
state
,
struct
dhcp_context
*
context
,
struct
in6_addr
*
addr
,
unsigned
int
lease_time
,
time_t
now
);
static
int
add_local_addrs
(
struct
dhcp_context
*
context
);
struct
dhcp_netid
*
add_options
(
struct
state
*
state
,
struct
in6_addr
*
fallback
,
struct
dhcp_context
*
context
);
#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
#define opt6_type(opt) (opt6_uint(opt, -4, 2))
...
...
@@ -172,39 +193,49 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **
static
int
dhcp6_no_relay
(
int
msg_type
,
struct
in6_addr
*
link_address
,
struct
dhcp_netid
*
tags
,
struct
dhcp_context
*
context
,
int
interface
,
char
*
iface_name
,
struct
in6_addr
*
fallback
,
void
*
inbuff
,
size_t
sz
,
int
is_unicast
,
time_t
now
)
{
void
*
packet_options
=
inbuff
+
4
;
void
*
end
=
inbuff
+
sz
;
void
*
opt
,
*
oro
;
int
i
,
o
,
o1
;
unsigned
char
*
clid
=
NULL
;
int
clid_len
=
0
,
start_opts
;
struct
dhcp_netid
*
tagif
,
*
context_tags
=
NULL
;
char
*
client_hostname
=
NULL
,
*
hostname
=
NULL
;
char
*
domain
=
NULL
,
*
send_domain
=
NULL
;
void
*
opt
;
int
i
,
o
,
o1
,
start_opts
;
struct
dhcp_opt
*
opt_cfg
;
struct
dhcp_netid
*
tagif
;
struct
dhcp_config
*
config
=
NULL
;
struct
dhcp_netid
known_id
,
iface_id
,
v6_id
;
int
done_dns
=
0
,
hostname_auth
=
0
,
do_encap
=
0
;
unsigned
char
*
outmsgtypep
;
struct
dhcp_opt
*
opt_cfg
;
struct
dhcp_vendor
*
vendor
;
struct
dhcp_context
*
context_tmp
;
unsigned
int
xid
,
ignore
=
0
;
unsigned
int
fqdn_flags
=
0x01
;
/* default to send if we recieve no FQDN option */
unsigned
int
ignore
=
0
;
struct
state
state
;
state
.
packet_options
=
inbuff
+
4
;
state
.
end
=
inbuff
+
sz
;
state
.
clid
=
NULL
;
state
.
clid_len
=
0
;
state
.
context_tags
=
NULL
;
state
.
tags
=
tags
;
state
.
link_address
=
link_address
;
state
.
interface
=
interface
;
state
.
domain
=
NULL
;
state
.
send_domain
=
NULL
;
state
.
context
=
context
;
state
.
hostname_auth
=
0
;
state
.
hostname
=
NULL
;
state
.
client_hostname
=
NULL
;
state
.
iface_name
=
iface_name
;
state
.
fqdn_flags
=
0x01
;
/* default to send if we recieve no FQDN option */
/* set tag with name == interface */
iface_id
.
net
=
iface_name
;
iface_id
.
next
=
tags
;
tags
=
&
iface_id
;
iface_id
.
next
=
state
.
tags
;
state
.
tags
=
&
iface_id
;
/* set tag "dhcpv6" */
v6_id
.
net
=
"dhcpv6"
;
v6_id
.
next
=
tags
;
tags
=
&
v6_id
;
v6_id
.
next
=
state
.
tags
;
state
.
tags
=
&
v6_id
;
/* copy over transaction-id, and save pointer to message type */
outmsgtypep
=
put_opt6
(
inbuff
,
4
);
start_opts
=
save_counter
(
-
1
);
xid
=
outmsgtypep
[
3
]
|
outmsgtypep
[
2
]
<<
8
|
outmsgtypep
[
1
]
<<
16
;
state
.
xid
=
outmsgtypep
[
3
]
|
outmsgtypep
[
2
]
<<
8
|
outmsgtypep
[
1
]
<<
16
;
/* We're going to be linking tags from all context we use.
mark them as unused so we don't link one twice and break the list */
...
...
@@ -218,19 +249,19 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
inet_ntop
(
AF_INET6
,
&
context_tmp
->
end6
,
daemon
->
dhcp_buff2
,
ADDRSTRLEN
);
if
(
context_tmp
->
flags
&
(
CONTEXT_STATIC
))
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"%u available DHCPv6 subnet: %s/%d"
),
xid
,
daemon
->
dhcp_buff
,
context_tmp
->
prefix
);
state
.
xid
,
daemon
->
dhcp_buff
,
context_tmp
->
prefix
);
else
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"%u available DHCP range: %s -- %s"
),
xid
,
daemon
->
dhcp_buff
,
daemon
->
dhcp_buff2
);
state
.
xid
,
daemon
->
dhcp_buff
,
daemon
->
dhcp_buff2
);
}
}
if
((
opt
=
opt6_find
(
packet_options
,
end
,
OPTION6_CLIENT_ID
,
1
)))
if
((
opt
=
opt6_find
(
state
.
packet_options
,
state
.
end
,
OPTION6_CLIENT_ID
,
1
)))
{
clid
=
opt6_ptr
(
opt
,
0
);
clid_len
=
opt6_len
(
opt
);
state
.
clid
=
opt6_ptr
(
opt
,
0
);
state
.
clid_len
=
opt6_len
(
opt
);
o
=
new_opt6
(
OPTION6_CLIENT_ID
);
put_opt6
(
clid
,
clid_len
);
put_opt6
(
state
.
clid
,
state
.
clid_len
);
end_opt6
(
o
);
}
else
if
(
msg_type
!=
DHCP6IREQ
)
...
...
@@ -238,7 +269,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
/* server-id must match except for SOLICIT and CONFIRM messages */
if
(
msg_type
!=
DHCP6SOLICIT
&&
msg_type
!=
DHCP6CONFIRM
&&
msg_type
!=
DHCP6IREQ
&&
(
!
(
opt
=
opt6_find
(
packet_options
,
end
,
OPTION6_SERVER_ID
,
1
))
||
(
!
(
opt
=
opt6_find
(
state
.
packet_options
,
state
.
end
,
OPTION6_SERVER_ID
,
1
))
||
opt6_len
(
opt
)
!=
daemon
->
duid_len
||
memcmp
(
opt6_ptr
(
opt
,
0
),
daemon
->
duid
,
daemon
->
duid_len
)
!=
0
))
return
0
;
...
...
@@ -270,7 +301,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
else
continue
;
if
((
opt
=
opt6_find
(
packet_options
,
end
,
mopt
,
2
)))
if
((
opt
=
opt6_find
(
state
.
packet_options
,
state
.
end
,
mopt
,
2
)))
{
void
*
enc_opt
,
*
enc_end
=
opt6_ptr
(
opt
,
opt6_len
(
opt
));
int
offset
=
0
;
...
...
@@ -290,15 +321,15 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
for
(
i
=
0
;
i
<=
(
opt6_len
(
enc_opt
)
-
vendor
->
len
);
i
++
)
if
(
memcmp
(
vendor
->
data
,
opt6_ptr
(
enc_opt
,
i
),
vendor
->
len
)
==
0
)
{
vendor
->
netid
.
next
=
tags
;
tags
=
&
vendor
->
netid
;
vendor
->
netid
.
next
=
state
.
tags
;
state
.
tags
=
&
vendor
->
netid
;
break
;
}
}
}
if
(
option_bool
(
OPT_LOG_OPTS
)
&&
(
opt
=
opt6_find
(
packet_options
,
end
,
OPTION6_VENDOR_CLASS
,
4
)))
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"%u vendor class: %u"
),
xid
,
opt6_uint
(
opt
,
0
,
4
));
if
(
option_bool
(
OPT_LOG_OPTS
)
&&
(
opt
=
opt6_find
(
state
.
packet_options
,
state
.
end
,
OPTION6_VENDOR_CLASS
,
4
)))
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"%u vendor class: %u"
),
state
.
xid
,
opt6_uint
(
opt
,
0
,
4
));
/* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
Otherwise assume the option is an array, and look for a matching element.
...
...
@@ -310,9 +341,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if
(
opt_cfg
->
flags
&
DHOPT_RFC3925
)
{
for
(
opt
=
opt6_find
(
packet_options
,
end
,
OPTION6_VENDOR_OPTS
,
4
);
for
(
opt
=
opt6_find
(
state
.
packet_options
,
state
.
end
,
OPTION6_VENDOR_OPTS
,
4
);
opt
;
opt
=
opt6_find
(
opt6_next
(
opt
,
end
),
end
,
OPTION6_VENDOR_OPTS
,
4
))
opt
=
opt6_find
(
opt6_next
(
opt
,
state
.
end
),
state
.
end
,
OPTION6_VENDOR_OPTS
,
4
))
{
void
*
vopt
;
void
*
vend
=
opt6_ptr
(
opt
,
opt6_len
(
opt
));
...
...
@@ -328,7 +359,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
}
else
{
if
(
!
(
opt
=
opt6_find
(
packet_options
,
end
,
opt_cfg
->
opt
,
1
)))
if
(
!
(
opt
=
opt6_find
(
state
.
packet_options
,
state
.
end
,
opt_cfg
->
opt
,
1
)))
continue
;
match
=
match_bytes
(
opt_cfg
,
opt6_ptr
(
opt
,
0
),
opt6_len
(
opt
));
...
...
@@ -336,23 +367,23 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if
(
match
)
{
opt_cfg
->
netid
->
next
=
tags
;
tags
=
opt_cfg
->
netid
;
opt_cfg
->
netid
->
next
=
state
.
tags
;
state
.
tags
=
opt_cfg
->
netid
;
}
}
if
((
opt
=
opt6_find
(
packet_options
,
end
,
OPTION6_FQDN
,
1
)))
if
((
opt
=
opt6_find
(
state
.
packet_options
,
state
.
end
,
OPTION6_FQDN
,
1
)))
{
/* RFC4704 refers */
int
len
=
opt6_len
(
opt
)
-
1
;
fqdn_flags
=
opt6_uint
(
opt
,
0
,
1
);
state
.
fqdn_flags
=
opt6_uint
(
opt
,
0
,
1
);
/* Always force update, since the client has no way to do it itself. */
if
(
!
option_bool
(
OPT_FQDN_UPDATE
)
&&
!
(
fqdn_flags
&
0x01
))
fqdn_flags
|=
0x03
;
if
(
!
option_bool
(
OPT_FQDN_UPDATE
)
&&
!
(
state
.
fqdn_flags
&
0x01
))
state
.
fqdn_flags
|=
0x03
;
fqdn_flags
&=
~
0x04
;
state
.
fqdn_flags
&=
~
0x04
;
if
(
len
!=
0
&&
len
<
255
)
{
...
...
@@ -374,36 +405,36 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if
(
legal_hostname
(
daemon
->
dhcp_buff
))
{
client_hostname
=
daemon
->
dhcp_buff
;
state
.
client_hostname
=
daemon
->
dhcp_buff
;
if
(
option_bool
(
OPT_LOG_OPTS
))
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"%u client provides name: %s"
),
xid
,
client_hostname
);
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"%u client provides name: %s"
),
state
.
xid
,
state
.
client_hostname
);
}
}
}
if
(
clid
)
if
(
state
.
clid
)
{
config
=
find_config6
(
daemon
->
dhcp_conf
,
context
,
clid
,
clid_len
,
NULL
);
config
=
find_config6
(
daemon
->
dhcp_conf
,
context
,
state
.
clid
,
state
.
clid_len
,
NULL
);
if
(
have_config
(
config
,
CONFIG_NAME
))
{
hostname
=
config
->
hostname
;
domain
=
config
->
domain
;
hostname_auth
=
1
;
state
.
hostname
=
config
->
hostname
;
state
.
domain
=
config
->
domain
;
state
.
hostname_auth
=
1
;
}
else
if
(
client_hostname
)
else
if
(
state
.
client_hostname
)
{
domain
=
strip_hostname
(
client_hostname
);
state
.
domain
=
strip_hostname
(
state
.
client_hostname
);
if
(
strlen
(
client_hostname
)
!=
0
)
if
(
strlen
(
state
.
client_hostname
)
!=
0
)
{
hostname
=
client_hostname
;
state
.
hostname
=
state
.
client_hostname
;
if
(
!
config
)
{
/* Search again now we have a hostname.
Only accept configs without CLID here, (it won't match)
to avoid impersonation by name. */
struct
dhcp_config
*
new
=
find_config6
(
daemon
->
dhcp_conf
,
context
,
NULL
,
0
,
hostname
);
struct
dhcp_config
*
new
=
find_config6
(
daemon
->
dhcp_conf
,
context
,
NULL
,
0
,
state
.
hostname
);
if
(
new
&&
!
have_config
(
new
,
CONFIG_CLID
)
&&
!
new
->
hwaddr
)
config
=
new
;
}
...
...
@@ -417,20 +448,20 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
for
(
list
=
config
->
netid
;
list
;
list
=
list
->
next
)
{
list
->
list
->
next
=
tags
;
tags
=
list
->
list
;
list
->
list
->
next
=
state
.
tags
;
state
.
tags
=
list
->
list
;
}
/* set "known" tag for known hosts */
known_id
.
net
=
"known"
;
known_id
.
next
=
tags
;
tags
=
&
known_id
;
known_id
.
next
=
state
.
tags
;
state
.
tags
=
&
known_id
;
if
(
have_config
(
config
,
CONFIG_DISABLE
))
ignore
=
1
;
}
tagif
=
run_tag_if
(
tags
);
tagif
=
run_tag_if
(
state
.
tags
);
/* if all the netids in the ignore list are present, ignore this client */
if
(
daemon
->
dhcp_ignore
)
...
...
@@ -443,7 +474,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
}
/* if all the netids in the ignore_name list are present, ignore client-supplied name */
if
(
!
hostname_auth
)
if
(
!
state
.
hostname_auth
)
{
struct
dhcp_netid_list
*
id_list
;
...
...
@@ -451,7 +482,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if
((
!
id_list
->
list
)
||
match_netid
(
id_list
->
list
,
tagif
,
0
))
break
;
if
(
id_list
)
hostname
=
NULL
;
state
.
hostname
=
NULL
;
}
...
...
@@ -460,12 +491,11 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
default:
return
0
;
case
DHCP6SOLICIT
:
case
DHCP6REQUEST
:
{
void
*
rapid_commit
=
opt6_find
(
packet_options
,
end
,
OPTION6_RAPID_COMMIT
,
0
);
int
make_lease
=
(
msg_type
==
DHCP6REQUEST
||
rapid_commit
);
int
serial
=
0
,
used_config
=
0
;
void
*
rapid_commit
=
opt6_find
(
state
.
packet_options
,
state
.
end
,
OPTION6_RAPID_COMMIT
,
0
);
int
used_config
=
0
,
address_assigned
=
0
;
if
(
rapid_commit
)
{
...
...
@@ -474,319 +504,233 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
}
/* set reply message type */
*
outmsgtypep
=
make_lease
?
DHCP6REPLY
:
DHCP6ADVERTISE
;
*
outmsgtypep
=
rapid_commit
?
DHCP6REPLY
:
DHCP6ADVERTISE
;
log6_packet
(
msg_type
==
DHCP6SOLICIT
?
"DHCPSOLICIT"
:
"DHCPREQUEST"
,
clid
,
clid_len
,
NULL
,
xid
,
iface_name
,
ignore
?
"ignored"
:
NULL
);
log6_packet
(
&
state
,
"DHCPSOLICIT"
,
NULL
,
ignore
?
"ignored"
:
NULL
);
if
(
ignore
)
return
0
;
for
(
opt
=
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
end
))
for
(
opt
=
state
.
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
state
.
end
))
{
int
iaid
,
ia_type
=
opt6_type
(
opt
);
void
*
ia_option
,
*
ia_end
;
unsigned
int
min_time
=
0xffffffff
;
int
t1cntr
=
0
;
int
address_assigned
=
0
;
if
(
ia_type
!=
OPTION6_IA_NA
&&
ia_type
!=
OPTION6_IA_TA
)
continue
;
if
(
ia_type
==
OPTION6_IA_NA
&&
opt6_len
(
opt
)
<
12
)
continue
;
int
t1cntr
;
int
config_ok
=
0
;
struct
dhcp_context
*
c
;
u32
lease_time
,
requested_time
;
struct
dhcp_lease
*
ltmp
;
struct
in6_addr
*
req_addr
;
struct
in6_addr
addr
;
if
(
ia_type
==
OPTION6_IA_TA
&&
opt6_len
(
opt
)
<
4
)
if
(
!
(
ia_option
=
check_ia
(
&
state
,
opt
,
&
ia_end
))
)
continue
;
i
aid
=
opt6_uint
(
opt
,
0
,
4
);
ia_end
=
opt6_ptr
(
opt
,
opt6_len
(
opt
));
ia_option
=
opt6_find
(
opt6_ptr
(
opt
,
ia_type
==
OPTION6_IA_NA
?
12
:
4
),
ia_end
,
OPTION6_IAADDR
,
24
);
i
f
(
have_config
(
config
,
CONFIG_ADDR6
))
{
struct
dhcp_lease
*
config_lease
=
lease6_find_by_addr
(
&
config
->
addr6
,
128
,
0
);
/* reset "USED" flags on leases */
lease6_filter
(
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
context
);
config_ok
=
1
;
o
=
new_opt6
(
ia_type
);
put_opt6_long
(
iaid
);
if
(
ia_type
==
OPTION6_IA_NA
)
{
/* save pointer */
t1cntr
=
save_counter
(
-
1
);
/* so we can fill these in later */
put_opt6_long
(
0
);
put_opt6_long
(
0
);
if
(
config_lease
&&
(
config_lease
->
clid_len
!=
state
.
clid_len
||
memcmp
(
config_lease
->
clid
,
state
.
clid
,
state
.
clid_len
)
!=
0
||
config_lease
->
hwaddr_type
!=
state
.
iaid
))
config_ok
=
0
;
/* configured address leased elsewhere */
}
while
(
1
)
{
struct
in6_addr
alloced_addr
,
*
addrp
=
NULL
;
u32
requested_time
=
0
;
struct
dhcp_lease
*
lease
=
NULL
;
/* reset USED bits in leases */
lease6_reset
();
o
=
build_ia
(
&
state
,
&
t1cntr
);
if
(
ia_option
)
for
(;
ia_option
;
ia_option
=
opt6_find
(
opt6_next
(
ia_option
,
ia_end
),
ia_end
,
OPTION6_IAADDR
,
24
)
)
{
struct
in6_addr
*
req_addr
=
opt6_ptr
(
ia_option
,
0
);
req_addr
=
opt6_ptr
(
ia_option
,
0
);
ltmp
=
lease6_find_by_addr
(
req_addr
,
128
,
0
);
requested_time
=
opt6_uint
(
ia_option
,
16
,
4
);
struct
dhcp_context
*
dynamic
;
if
((
dynamic
=
address6_available
(
context
,
req_addr
,
tags
))
||
address6_valid
(
context
,
req_addr
,
tags
))
{
if
(
!
dynamic
&&
!
(
have_config
(
config
,
CONFIG_ADDR6
)
&&
memcmp
(
&
config
->
addr6
,
req_addr
,
IN6ADDRSZ
)
==
0
))
/* reset USED bits in contexts - one address per prefix per IAID */
for
(
c
=
context
;
c
;
c
=
c
->
current
)
c
->
flags
&=
~
CONTEXT_USED
;
if
((
c
=
address6_valid
(
context
,
req_addr
,
tagif
)))
{
/* Static range, not configured. */
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6UNSPEC
);
put_opt6_string
(
"Address unavailable"
);
end_opt6
(
o1
);
}
else
if
(
lease6_find_by_addr
(
req_addr
,
128
,
0
)
&&
!
(
lease
=
lease6_find
(
clid
,
clid_len
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
req_addr
)))
lease_time
=
c
->
lease_time
;
/* If the client asks for an address on the same network as a configured address,
offer the configured address instead, to make moving to newly-configured
addresses automatic. */
if
(
!
used_config
&&
config_ok
&&
is_same_net6
(
req_addr
,
&
config
->
addr6
,
c
->
prefix
))
{
/* Address leased to another DUID/IAID */
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6UNSPEC
);
put_opt6_string
(
"Address in use"
);
end_opt6
(
o1
);
req_addr
=
&
config
->
addr6
;
used_config
=
1
;
if
(
have_config
(
config
,
CONFIG_TIME
))
lease_time
=
config
->
lease_time
;
}
else
if
(
!
(
c
=
address6_available
(
context
,
req_addr
,
tagif
)))
continue
;
/* not an address we're allowed */
else
if
(
ltmp
&&
(
ltmp
->
clid_len
!=
state
.
clid_len
||
memcmp
(
ltmp
->
clid
,
state
.
clid
,
state
.
clid_len
)
!=
0
||
ltmp
->
hwaddr_type
!=
state
.
iaid
))
continue
;
/* address leased elsewhere */
/* add address to output packet */
add_address
(
&
state
,
c
,
lease_time
,
requested_time
,
&
min_time
,
req_addr
,
rapid_commit
!=
NULL
,
now
);
get_context_tag
(
&
state
,
c
);
address_assigned
=
1
;
}
else
addrp
=
req_addr
;
}
else
if
(
msg_type
==
DHCP6REQUEST
)
/* Suggest configured address */
if
(
!
used_config
&&
config_ok
&&
(
c
=
address6_valid
(
context
,
&
config
->
addr6
,
tagif
)))
{
/* requested address not on the correct link */
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6NOTONLINK
);
put_opt6_string
(
"Not on link"
);
end_opt6
(
o1
);
}
used_config
=
1
;
if
(
have_config
(
config
,
CONFIG_TIME
))
lease_time
=
config
->
lease_time
;
/* add address to output packet */
add_address
(
&
state
,
c
,
lease_time
,
requested_time
,
&
min_time
,
&
config
->
addr6
,
rapid_commit
!=
NULL
,
now
);
get_context_tag
(
&
state
,
c
);
address_assigned
=
1
;
}
else
{
/* must have an address to CONFIRM */
if
(
msg_type
==
DHCP6REQUEST
&&
ia_type
==
OPTION6_IA_NA
)
return
0
;
/* Don't used configured addresses for temporary leases. */
if
(
have_config
(
config
,
CONFIG_ADDR6
)
&&
!
used_config
&&
ia_type
==
OPTION6_IA_NA
)
/* return addresses for existing leases */
ltmp
=
NULL
;
while
((
ltmp
=
lease6_find_by_client
(
ltmp
,
state
.
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
state
.
clid
,
state
.
clid_len
,
state
.
iaid
)))
{
struct
dhcp_lease
*
ltmp
=
lease6_find_by_addr
(
&
config
->
addr6
,
128
,
0
);
used_config
=
1
;
inet_ntop
(
AF_INET6
,
&
config
->
addr6
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
if
(
ltmp
&&
ltmp
->
clid
&&
(
ltmp
->
clid_len
!=
clid_len
||
memcmp
(
ltmp
->
clid
,
clid
,
clid_len
)
!=
0
||
ltmp
->
hwaddr_type
!=
iaid
))
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"not using configured address %s because it is leased to %s#%d"
),
daemon
->
addrbuff
,
print_mac
(
daemon
->
namebuff
,
ltmp
->
clid
,
ltmp
->
clid_len
),
ltmp
->
hwaddr_type
);
else
if
(
have_config
(
config
,
CONFIG_DECLINED
)
&&
difftime
(
now
,
config
->
decline_time
)
<
(
float
)
DECLINE_BACKOFF
)
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"not using configured address %s because it was previously declined"
),
daemon
->
addrbuff
);
else
req_addr
=
(
struct
in6_addr
*
)
ltmp
->
hwaddr
;
if
((
c
=
address6_available
(
context
,
req_addr
,
tagif
)))
{
addrp
=
&
config
->
addr6
;
/* may have existing lease for this address */
lease
=
lease6_find
(
clid
,
clid_len
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
addrp
);
add_address
(
&
state
,
c
,
c
->
lease_time
,
c
->
lease_time
,
&
min_time
,
req_addr
,
rapid_commit
!=
NULL
,
now
);
get_context_tag
(
&
state
,
c
);
address_assigned
=
1
;
}
}
/* existing lease */
if
(
!
addrp
&&
(
lease
=
lease6_find
(
clid
,
clid_len
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
NULL
))
&&
!
config_find_by_address6
(
daemon
->
dhcp_conf
,
(
struct
in6_addr
*
)
&
lease
->
hwaddr
,
128
,
0
))
addrp
=
(
struct
in6_addr
*
)
&
lease
->
hwaddr
;
/* Return addresses for all valid contexts which don't yet have one */
while
((
c
=
address6_allocate
(
c
,
state
.
clid
,
state
.
clid_len
,
state
.
iaid
,
tagif
,
&
addr
)))
{
add_address
(
&
state
,
c
,
c
->
lease_time
,
c
->
lease_time
,
&
min_time
,
&
addr
,
rapid_commit
!=
NULL
,
now
);
get_context_tag
(
&
state
,
c
);
address_assigned
=
1
;
}
if
(
!
addrp
&&
address6_allocate
(
context
,
clid
,
clid_len
,
serial
++
,
tags
,
&
alloced_addr
))
addrp
=
&
alloced_addr
;
end_ia
(
t1cntr
,
min_time
,
0
);
end_opt6
(
o
);
}
if
(
addrp
)
if
(
address_assigned
)
{
unsigned
int
lease_time
;
struct
dhcp_context
*
this_context
;
struct
dhcp_config
*
valid_config
=
config
;
/* don't use a config to set lease time if it specifies an address which isn't this. */
if
(
have_config
(
config
,
CONFIG_ADDR6
)
&&
memcmp
(
&
config
->
addr6
,
addrp
,
IN6ADDRSZ
)
!=
0
)
valid_config
=
NULL
;
address_assigned
=
1
;
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6SUCCESS
);
put_opt6_string
(
"Oh hai from dnsmasq"
);
end_opt6
(
o1
);
/* shouldn't ever fail */
if
((
this_context
=
narrow_context6
(
context
,
addrp
,
tagif
)))
{
/* get tags from context if we've not used it before */
if
(
this_context
->
netid
.
next
==
&
this_context
->
netid
&&
this_context
->
netid
.
net
)
{
this_context
->
netid
.
next
=
context_tags
;
context_tags
=
&
this_context
->
netid
;
if
(
!
hostname_auth
)
/* If --dhcp-authoritative is set, we can tell client not to wait for
other possible servers */
o
=
new_opt6
(
OPTION6_PREFERENCE
);
put_opt6_char
(
option_bool
(
OPT_AUTHORITATIVE
)
?
255
:
0
);
end_opt6
(
o
);
}
else
{
struct
dhcp_netid_list
*
id_list
;
/* no address, return error */
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6NOADDRS
);
put_opt6_string
(
"No addresses available"
);
end_opt6
(
o1
);
}
for
(
id_list
=
daemon
->
dhcp_ignore_names
;
id_list
;
id_list
=
id_list
->
next
)
if
((
!
id_list
->
list
)
||
match_netid
(
id_list
->
list
,
&
this_context
->
netid
,
0
))
tagif
=
add_options
(
&
state
,
fallback
,
context
);
break
;
if
(
id_list
)
hostname
=
NULL
;
}
}
if
(
have_config
(
valid_config
,
CONFIG_TIME
))
lease_time
=
valid_config
->
lease_time
;
else
lease_time
=
this_context
->
lease_time
;
if
(
this_context
->
valid
<
lease_time
)
lease_time
=
this_context
->
valid
;
if
(
ia_option
)
case
DHCP6REQUEST
:
{
if
(
requested_time
<
120u
)
requested_time
=
120u
;
/* sanity */
if
(
lease_time
==
0xffffffff
||
(
requested_time
!=
0xffffffff
&&
requested_time
<
lease_time
))
lease_time
=
requested_time
;
}
int
address_assigned
=
0
;
if
(
lease_time
<
min_time
)
min_time
=
lease_time
;
/* set reply message type */
*
outmsgtypep
=
DHCP6REPLY
;
/* May fail to create lease */
if
(
!
lease
&&
make_lease
)
lease
=
lease6_allocate
(
addrp
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
);
log6_packet
(
&
state
,
"DHCPREQUEST"
,
NULL
,
ignore
?
"ignored"
:
NULL
);
if
(
lease
)
{
lease_set_expires
(
lease
,
lease_time
,
now
);
lease_set_hwaddr
(
lease
,
NULL
,
clid
,
0
,
iaid
,
clid_len
,
now
,
0
);
lease_set_interface
(
lease
,
interface
,
now
);
if
(
hostname
&&
ia_type
==
OPTION6_IA_NA
)
{
char
*
addr_domain
=
get_domain6
(
addrp
);
if
(
!
send_domain
)
send_domain
=
addr_domain
;
lease_set_hostname
(
lease
,
hostname
,
hostname_auth
,
addr_domain
,
domain
);
}
#ifdef HAVE_SCRIPT
if
(
daemon
->
lease_change_command
)
{
void
*
class_opt
;
lease
->
flags
|=
LEASE_CHANGED
;
free
(
lease
->
extradata
);
lease
->
extradata
=
NULL
;
lease
->
extradata_size
=
lease
->
extradata_len
=
0
;
lease
->
hwaddr_len
=
0
;
/* surrogate for no of vendor classes */
if
(
ignore
)
return
0
;
if
((
class_opt
=
opt6_find
(
packet_options
,
end
,
OPTION6_VENDOR_CLASS
,
4
)
))
for
(
opt
=
state
.
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
state
.
end
))
{
void
*
enc_opt
,
*
enc_end
=
opt6_ptr
(
class_opt
,
opt6_len
(
class_opt
));
lease
->
hwaddr_len
++
;
/* send enterprise number first */
sprintf
(
daemon
->
dhcp_buff2
,
"%u"
,
opt6_uint
(
class_opt
,
0
,
4
));
lease_add_extradata
(
lease
,
(
unsigned
char
*
)
daemon
->
dhcp_buff2
,
strlen
(
daemon
->
dhcp_buff2
),
0
);
void
*
ia_option
,
*
ia_end
;
unsigned
int
min_time
=
0xffffffff
;
int
t1cntr
;
if
(
opt6_len
(
class_opt
)
>=
6
)
for
(
enc_opt
=
opt6_ptr
(
class_opt
,
4
);
enc_opt
;
enc_opt
=
opt6_next
(
enc_opt
,
enc_end
))
{
lease
->
hwaddr_len
++
;
lease_add_extradata
(
lease
,
opt6_ptr
(
enc_opt
,
0
),
opt6_len
(
enc_opt
),
0
);
}
}
if
(
!
(
ia_option
=
check_ia
(
&
state
,
opt
,
&
ia_end
)))
continue
;
lease_add_extradata
(
lease
,
(
unsigned
char
*
)
client_hostname
,
client_hostname
?
strlen
(
client_hostname
)
:
0
,
0
);
o
=
build_ia
(
&
state
,
&
t1cntr
);
/* space-concat tag set */
if
(
!
tagif
&&
!
context_tags
)
lease_add_extradata
(
lease
,
NULL
,
0
,
0
);
else
for
(;
ia_option
;
ia_option
=
opt6_find
(
opt6_next
(
ia_option
,
ia_end
),
ia_end
,
OPTION6_IAADDR
,
24
))
{
struct
dhcp_netid
*
n
,
*
l
,
*
tmp
=
tags
;
struct
in6_addr
*
req_addr
=
opt6_ptr
(
ia_option
,
0
);
u32
requested_time
=
opt6_uint
(
ia_option
,
16
,
4
);
struct
dhcp_context
*
dynamic
,
*
c
;
unsigned
int
lease_time
;
/* link temporarily */
for
(
n
=
context_tags
;
n
&&
n
->
next
;
n
=
n
->
next
);
if
((
l
=
n
))
if
((
dynamic
=
address6_available
(
context
,
req_addr
,
tagif
))
||
(
c
=
address6_valid
(
context
,
req_addr
,
tagif
)))
{
l
->
next
=
tags
;
tmp
=
context_tags
;
}
for
(
n
=
run_tag_if
(
tmp
);
n
;
n
=
n
->
next
)
if
(
!
dynamic
&&
!
(
have_config
(
config
,
CONFIG_ADDR6
)
||
!
IN6_ARE_ADDR_EQUAL
(
&
config
->
addr6
,
req_addr
)))
{
struct
dhcp_netid
*
n1
;
/* kill dupes */
for
(
n1
=
n
->
next
;
n1
;
n1
=
n1
->
next
)
if
(
strcmp
(
n
->
net
,
n1
->
net
)
==
0
)
break
;
if
(
!
n1
)
lease_add_extradata
(
lease
,
(
unsigned
char
*
)
n
->
net
,
strlen
(
n
->
net
),
n
->
next
?
' '
:
0
);
/* Static range, not configured. */
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6UNSPEC
);
put_opt6_string
(
"Address unavailable"
);
end_opt6
(
o1
);
}
/* unlink again */
if
(
l
)
l
->
next
=
NULL
;
else
if
(
lease6_find_by_addr
(
req_addr
,
128
,
0
)
&&
!
lease6_find
(
state
.
clid
,
state
.
clid_len
,
state
.
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
state
.
iaid
,
req_addr
))
{
/* Address leased to another DUID/IAID */
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6UNSPEC
);
put_opt6_string
(
"Address in use"
);
end_opt6
(
o1
);
}
else
{
if
(
!
dynamic
)
dynamic
=
c
;
if
(
link_address
)
inet_ntop
(
AF_INET6
,
link_address
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
lease_time
=
dynamic
->
lease_time
;
lease_add_extradata
(
lease
,
(
unsigned
char
*
)
daemon
->
addrbuff
,
link_address
?
strlen
(
daemon
->
addrbuff
)
:
0
,
0
);
if
(
have_config
(
config
,
CONFIG_ADDR6
)
&&
IN6_ARE_ADDR_EQUAL
(
&
config
->
addr6
,
req_addr
)
&&
have_config
(
config
,
CONFIG_TIME
))
lease_time
=
config
->
lease_time
;
if
((
class_opt
=
opt6_find
(
packet_options
,
end
,
OPTION6_USER_CLASS
,
2
)))
{
void
*
enc_opt
,
*
enc_end
=
opt6_ptr
(
class_opt
,
opt6_len
(
class_opt
));
for
(
enc_opt
=
opt6_ptr
(
class_opt
,
0
);
enc_opt
;
enc_opt
=
opt6_next
(
enc_opt
,
enc_end
))
lease_add_extradata
(
lease
,
opt6_ptr
(
enc_opt
,
0
),
opt6_len
(
enc_opt
),
0
);
}
add_address
(
&
state
,
dynamic
,
lease_time
,
requested_time
,
&
min_time
,
req_addr
,
1
,
now
);
get_context_tag
(
&
state
,
dynamic
);
address_assigned
=
1
;
}
#endif
}
else
if
(
!
send_domain
)
send_domain
=
get_domain6
(
addrp
);
if
(
lease
||
!
make_lease
)
else
if
(
msg_type
==
DHCP6REQUEST
)
{
o1
=
new_opt6
(
OPTION6_IAADDR
);
put_opt6
(
addrp
,
sizeof
(
*
addrp
));
/* preferred lifetime */
put_opt6_long
(
this_context
&&
(
this_context
->
preferred
<
lease_time
)
?
this_context
->
preferred
:
lease_time
);
put_opt6_long
(
lease_time
);
/* valid lifetime */
/* requested address not on the correct link */
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6NOTONLINK
);
put_opt6_string
(
"Not on link"
);
end_opt6
(
o1
);
log6_packet
(
make_lease
?
"DHCPREPLY"
:
"DHCPADVERTISE"
,
clid
,
clid_len
,
addrp
,
xid
,
iface_name
,
hostname
);
}
}
}
end_ia
(
t1cntr
,
min_time
,
0
);
end_opt6
(
o
);
}
if
(
!
ia_option
||
!
(
ia_option
=
opt6_find
(
opt6_next
(
ia_option
,
ia_end
),
ia_end
,
OPTION6_IAADDR
,
24
)))
{
if
(
address_assigned
)
{
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6SUCCESS
);
put_opt6_string
(
"Oh hai from dnsmasq"
);
end_opt6
(
o1
);
if
(
ia_type
==
OPTION6_IA_NA
)
{
/* go back an fill in fields in IA_NA option */
unsigned
int
t1
=
min_time
==
0xffffffff
?
0xffffffff
:
min_time
/
2
;
unsigned
int
t2
=
min_time
==
0xffffffff
?
0xffffffff
:
(
min_time
/
8
)
*
7
;
int
sav
=
save_counter
(
t1cntr
);
put_opt6_long
(
t1
);
put_opt6_long
(
t2
);
save_counter
(
sav
);
}
}
else
{
...
...
@@ -797,73 +741,31 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
end_opt6
(
o1
);
}
end_opt6
(
o
);
if
(
address_assigned
)
{
/* If --dhcp-authoritative is set, we can tell client not to wait for
other possible servers */
o
=
new_opt6
(
OPTION6_PREFERENCE
);
put_opt6_char
(
option_bool
(
OPT_AUTHORITATIVE
)
?
255
:
0
);
end_opt6
(
o
);
}
tagif
=
add_options
(
&
state
,
fallback
,
context
);
break
;
}
}
}
break
;
}
case
DHCP6RENEW
:
{
/* set reply message type */
*
outmsgtypep
=
DHCP6REPLY
;
log6_packet
(
"DHCPRENEW"
,
clid
,
clid_len
,
NULL
,
xid
,
iface_name
,
NULL
);
log6_packet
(
&
state
,
"DHCPRENEW"
,
NULL
,
NULL
);
for
(
opt
=
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
end
))
for
(
opt
=
state
.
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
state
.
end
))
{
int
ia_type
=
opt6_type
(
opt
);
void
*
ia_option
,
*
ia_end
;
unsigned
int
min_time
=
0xffffffff
;
int
t1cntr
=
0
,
iacntr
;
unsigned
int
iaid
;
if
(
ia_type
!=
OPTION6_IA_NA
&&
ia_type
!=
OPTION6_IA_TA
)
continue
;
int
t1cntr
,
iacntr
;
if
(
ia_type
==
OPTION6_IA_NA
&&
opt6_len
(
opt
)
<
12
)
if
(
!
(
ia_option
=
check_ia
(
&
state
,
opt
,
&
ia_end
))
)
continue
;
if
(
ia_type
==
OPTION6_IA_TA
&&
opt6_len
(
opt
)
<
4
)
continue
;
iaid
=
opt6_uint
(
opt
,
0
,
4
);
o
=
new_opt6
(
ia_type
);
put_opt6_long
(
iaid
);
if
(
ia_type
==
OPTION6_IA_NA
)
{
/* save pointer */
t1cntr
=
save_counter
(
-
1
);
/* so we can fill these in later */
put_opt6_long
(
0
);
put_opt6_long
(
0
);
}
o
=
build_ia
(
&
state
,
&
t1cntr
);
iacntr
=
save_counter
(
-
1
);
/* reset "USED" flags on leases */
lease6_filter
(
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
context
);
ia_option
=
opt6_ptr
(
opt
,
ia_type
==
OPTION6_IA_NA
?
12
:
4
);
ia_end
=
opt6_ptr
(
opt
,
opt6_len
(
opt
));
for
(
ia_option
=
opt6_find
(
ia_option
,
ia_end
,
OPTION6_IAADDR
,
24
);
ia_option
;
ia_option
=
opt6_find
(
opt6_next
(
ia_option
,
ia_end
),
ia_end
,
OPTION6_IAADDR
,
24
))
for
(;
ia_option
;
ia_option
=
opt6_find
(
opt6_next
(
ia_option
,
ia_end
),
ia_end
,
OPTION6_IAADDR
,
24
))
{
struct
dhcp_lease
*
lease
=
NULL
;
struct
in6_addr
*
req_addr
=
opt6_ptr
(
ia_option
,
0
);
...
...
@@ -873,12 +775,12 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
struct
dhcp_config
*
valid_config
=
config
;
/* don't use a config to set lease time if it specifies an address which isn't this. */
if
(
have_config
(
config
,
CONFIG_ADDR6
)
&&
memcmp
(
&
config
->
addr6
,
req_addr
,
IN6ADDRSZ
)
!=
0
)
if
(
have_config
(
config
,
CONFIG_ADDR6
)
&&
!
IN6_ARE_ADDR_EQUAL
(
&
config
->
addr6
,
req_addr
)
)
valid_config
=
NULL
;
if
(
!
(
lease
=
lease6_find
(
clid
,
clid_len
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
req_addr
)))
if
(
!
(
lease
=
lease6_find
(
state
.
clid
,
state
.
clid_len
,
state
.
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
state
.
iaid
,
req_addr
)))
{
/* If the server cannot find a client entry for the IA the server
returns the IA containing no addresses with a Status Code option set
...
...
@@ -886,7 +788,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
save_counter
(
iacntr
);
t1cntr
=
0
;
log6_packet
(
"DHCPREPLY"
,
clid
,
clid_len
,
req_addr
,
xid
,
iface_name
,
"lease not found"
);
log6_packet
(
&
state
,
"DHCPREPLY"
,
req_addr
,
"lease not found"
);
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6NOBINDING
);
...
...
@@ -896,30 +798,10 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
}
if
(
!
address6_available
(
context
,
req_addr
,
tagif
)
||
!
(
this_context
=
narrow_context6
(
context
,
req_addr
,
tagif
)))
{
lease_time
=
0
;
this_context
=
NULL
;
}
else
{
/* get tags from context if we've not used it before */
if
(
this_context
->
netid
.
next
==
&
this_context
->
netid
&&
this_context
->
netid
.
net
)
if
((
this_context
!=
address6_available
(
context
,
req_addr
,
tagif
))
||
(
this_context
!=
address6_valid
(
context
,
req_addr
,
tagif
)))
{
this_context
->
netid
.
next
=
context_tags
;
context_tags
=
&
this_context
->
netid
;
if
(
!
hostname_auth
)
{
struct
dhcp_netid_list
*
id_list
;
for
(
id_list
=
daemon
->
dhcp_ignore_names
;
id_list
;
id_list
=
id_list
->
next
)
if
((
!
id_list
->
list
)
||
match_netid
(
id_list
->
list
,
&
this_context
->
netid
,
0
))
break
;
if
(
id_list
)
hostname
=
NULL
;
}
}
get_context_tag
(
&
state
,
this_context
);
lease_time
=
have_config
(
valid_config
,
CONFIG_TIME
)
?
valid_config
->
lease_time
:
this_context
->
lease_time
;
...
...
@@ -929,46 +811,33 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
lease_time
=
requested_time
;
lease_set_expires
(
lease
,
lease_time
,
now
);
if
(
ia_type
==
OPTION6_IA_NA
&&
hostname
)
if
(
state
.
ia_type
==
OPTION6_IA_NA
&&
state
.
hostname
)
{
char
*
addr_domain
=
get_domain6
(
req_addr
);
if
(
!
send_domain
)
send_domain
=
addr_domain
;
lease_set_hostname
(
lease
,
hostname
,
hostname_auth
,
addr_domain
,
domain
);
if
(
!
s
tate
.
s
end_domain
)
s
tate
.
s
end_domain
=
addr_domain
;
lease_set_hostname
(
lease
,
state
.
hostname
,
state
.
hostname_auth
,
addr_domain
,
state
.
domain
);
}
if
(
lease_time
<
min_time
)
min_time
=
lease_time
;
}
log6_packet
(
"DHCPREPLY"
,
clid
,
clid_len
,
req_addr
,
xid
,
iface_name
,
hostname
);
log6_packet
(
&
state
,
"DHCPREPLY"
,
req_addr
,
state
.
hostname
);
o1
=
new_opt6
(
OPTION6_IAADDR
);
put_opt6
(
req_addr
,
sizeof
(
*
req_addr
));
/* preferred lifetime */
put_opt6_long
(
this_context
&&
(
this_context
->
flags
&
CONTEXT_DEPRECATE
)
?
0
:
lease_time
);
put_opt6_long
(
lease_time
);
/* valid lifetime */
put_opt6_long
(
!
this_context
||
(
this_context
->
flags
&
CONTEXT_DEPRECATE
)
?
0
:
lease_time
);
put_opt6_long
(
!
this_context
?
0
:
lease_time
);
/* valid lifetime */
end_opt6
(
o1
);
}
if
(
t1cntr
!=
0
)
{
/* go back an fill in fields in IA_NA option */
int
sav
=
save_counter
(
t1cntr
);
unsigned
int
t1
,
t2
,
fuzz
=
rand16
();
while
(
fuzz
>
(
min_time
/
16
))
fuzz
=
fuzz
/
2
;
t1
=
min_time
==
0xffffffff
?
0xffffffff
:
min_time
/
2
-
fuzz
;
t2
=
min_time
==
0xffffffff
?
0xffffffff
:
((
min_time
/
8
)
*
7
)
-
fuzz
;
put_opt6_long
(
t1
);
put_opt6_long
(
t2
);
save_counter
(
sav
);
}
end_ia
(
t1cntr
,
min_time
,
1
);
end_opt6
(
o
);
}
tagif
=
add_options
(
&
state
,
fallback
,
context
);
break
;
}
...
...
@@ -978,32 +847,19 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
/* set reply message type */
*
outmsgtypep
=
DHCP6REPLY
;
log6_packet
(
"DHCPCONFIRM"
,
clid
,
clid_len
,
NULL
,
xid
,
iface_name
,
NULL
);
log6_packet
(
&
state
,
"DHCPCONFIRM"
,
NULL
,
NULL
);
for
(
opt
=
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
end
))
for
(
opt
=
state
.
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
state
.
end
))
{
int
ia_type
=
opt6_type
(
opt
);
void
*
ia_option
,
*
ia_end
;
if
(
ia_type
!=
OPTION6_IA_NA
&&
ia_type
!=
OPTION6_IA_TA
)
continue
;
if
(
ia_type
==
OPTION6_IA_NA
&&
opt6_len
(
opt
)
<
12
)
continue
;
if
(
ia_type
==
OPTION6_IA_TA
&&
opt6_len
(
opt
)
<
4
)
continue
;
ia_option
=
opt6_ptr
(
opt
,
ia_type
==
OPTION6_IA_NA
?
12
:
4
);
ia_end
=
opt6_ptr
(
opt
,
opt6_len
(
opt
));
for
(
ia_option
=
opt6_find
(
ia_option
,
ia_end
,
OPTION6_IAADDR
,
24
);
for
(
ia_option
=
check_ia
(
&
state
,
opt
,
&
ia_end
);
ia_option
;
ia_option
=
opt6_find
(
opt6_next
(
ia_option
,
ia_end
),
ia_end
,
OPTION6_IAADDR
,
24
))
{
struct
in6_addr
*
req_addr
=
opt6_ptr
(
ia_option
,
0
);
if
(
!
address6_available
(
context
,
req_addr
,
run_tag_if
(
tags
)
))
if
(
!
address6_available
(
context
,
req_addr
,
tagif
))
{
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6NOTONLINK
);
...
...
@@ -1012,7 +868,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
return
1
;
}
log6_packet
(
"DHCPREPLY"
,
clid
,
clid_len
,
req_addr
,
xid
,
iface_name
,
hostname
);
log6_packet
(
&
state
,
"DHCPREPLY"
,
req_addr
,
state
.
hostname
);
}
}
...
...
@@ -1020,7 +876,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
put_opt6_short
(
DHCP6SUCCESS
);
put_opt6_string
(
"All addresses still on link"
);
end_opt6
(
o1
);
return
1
;
break
;
}
case
DHCP6IREQ
:
...
...
@@ -1030,12 +886,13 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if
(
context
&&
context
->
netid
.
net
&&
!
context
->
current
)
{
context
->
netid
.
next
=
NULL
;
context_tags
=
&
context
->
netid
;
state
.
context_tags
=
&
context
->
netid
;
}
log6_packet
(
"DHCPINFORMATION-REQUEST"
,
clid
,
clid_len
,
NULL
,
xid
,
iface_name
,
ignore
?
"ignored"
:
hostname
);
log6_packet
(
&
state
,
"DHCPINFORMATION-REQUEST"
,
NULL
,
ignore
?
"ignored"
:
state
.
hostname
);
if
(
ignore
)
return
0
;
*
outmsgtypep
=
DHCP6REPLY
;
tagif
=
add_options
(
&
state
,
fallback
,
context
);
break
;
}
...
...
@@ -1045,46 +902,29 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
/* set reply message type */
*
outmsgtypep
=
DHCP6REPLY
;
log6_packet
(
"DHCPRELEASE"
,
clid
,
clid_len
,
NULL
,
xid
,
iface_name
,
NULL
);
log6_packet
(
&
state
,
"DHCPRELEASE"
,
NULL
,
NULL
);
for
(
opt
=
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
end
))
for
(
opt
=
state
.
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
state
.
end
))
{
int
iaid
,
ia_type
=
opt6_type
(
opt
);
void
*
ia_option
,
*
ia_end
;
int
made_ia
=
0
;
if
(
ia_type
!=
OPTION6_IA_NA
&&
ia_type
!=
OPTION6_IA_TA
)
continue
;
if
(
ia_type
==
OPTION6_IA_NA
&&
opt6_len
(
opt
)
<
12
)
continue
;
if
(
ia_type
==
OPTION6_IA_TA
&&
opt6_len
(
opt
)
<
4
)
continue
;
iaid
=
opt6_uint
(
opt
,
0
,
4
);
ia_end
=
opt6_ptr
(
opt
,
opt6_len
(
opt
));
ia_option
=
opt6_ptr
(
opt
,
ia_type
==
OPTION6_IA_NA
?
12
:
4
);
/* reset "USED" flags on leases */
lease6_filter
(
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
context
);
for
(
ia_option
=
opt6_find
(
ia_option
,
ia_end
,
OPTION6_IAADDR
,
24
);
for
(
ia_option
=
check_ia
(
&
state
,
opt
,
&
ia_end
);
ia_option
;
ia_option
=
opt6_find
(
opt6_next
(
ia_option
,
ia_end
),
ia_end
,
OPTION6_IAADDR
,
24
))
{
struct
dhcp_lease
*
lease
;
if
((
lease
=
lease6_find
(
clid
,
clid_len
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
opt6_ptr
(
ia_option
,
0
))))
if
((
lease
=
lease6_find
(
state
.
clid
,
state
.
clid_len
,
state
.
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
state
.
iaid
,
opt6_ptr
(
ia_option
,
0
))))
lease_prune
(
lease
,
now
);
else
{
if
(
!
made_ia
)
{
o
=
new_opt6
(
ia_type
);
put_opt6_long
(
iaid
);
if
(
ia_type
==
OPTION6_IA_NA
)
o
=
new_opt6
(
state
.
ia_type
);
put_opt6_long
(
state
.
iaid
);
if
(
state
.
ia_type
==
OPTION6_IA_NA
)
{
put_opt6_long
(
0
);
put_opt6_long
(
0
);
...
...
@@ -1116,7 +956,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
put_opt6_string
(
"Release received"
);
end_opt6
(
o1
);
return
1
;
break
;
}
case
DHCP6DECLINE
:
...
...
@@ -1124,39 +964,21 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
/* set reply message type */
*
outmsgtypep
=
DHCP6REPLY
;
log6_packet
(
"DHCPDECLINE"
,
clid
,
clid_len
,
NULL
,
xid
,
iface_name
,
NULL
);
log6_packet
(
&
state
,
"DHCPDECLINE"
,
NULL
,
NULL
);
for
(
opt
=
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
end
))
for
(
opt
=
state
.
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
state
.
end
))
{
int
iaid
,
ia_type
=
opt6_type
(
opt
);
void
*
ia_option
,
*
ia_end
;
int
made_ia
=
0
;
if
(
ia_type
!=
OPTION6_IA_NA
&&
ia_type
!=
OPTION6_IA_TA
)
continue
;
if
(
ia_type
==
OPTION6_IA_NA
&&
opt6_len
(
opt
)
<
12
)
continue
;
if
(
ia_type
==
OPTION6_IA_TA
&&
opt6_len
(
opt
)
<
4
)
continue
;
iaid
=
opt6_uint
(
opt
,
0
,
4
);
ia_end
=
opt6_ptr
(
opt
,
opt6_len
(
opt
));
ia_option
=
opt6_ptr
(
opt
,
ia_type
==
OPTION6_IA_NA
?
12
:
4
);
/* reset "USED" flags on leases */
lease6_filter
(
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
context
);
for
(
ia_option
=
opt6_find
(
ia_option
,
ia_end
,
OPTION6_IAADDR
,
24
);
for
(
ia_option
=
check_ia
(
&
state
,
opt
,
&
ia_end
);
ia_option
;
ia_option
=
opt6_find
(
opt6_next
(
ia_option
,
ia_end
),
ia_end
,
OPTION6_IAADDR
,
24
))
{
struct
dhcp_lease
*
lease
;
struct
in6_addr
*
addrp
=
opt6_ptr
(
ia_option
,
0
);
if
(
have_config
(
config
,
CONFIG_ADDR6
)
&&
memcmp
(
&
config
->
addr6
,
addrp
,
IN6ADDRSZ
)
==
0
)
if
(
have_config
(
config
,
CONFIG_ADDR6
)
&&
IN6_ARE_ADDR_EQUAL
(
&
config
->
addr6
,
addrp
))
{
prettyprint_time
(
daemon
->
dhcp_buff3
,
DECLINE_BACKOFF
);
inet_ntop
(
AF_INET6
,
addrp
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
...
...
@@ -1170,16 +992,16 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
for
(;
context
;
context
=
context
->
current
)
context
->
addr_epoch
++
;
if
((
lease
=
lease6_find
(
clid
,
clid_len
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
opt6_ptr
(
ia_option
,
0
))))
if
((
lease
=
lease6_find
(
state
.
clid
,
state
.
clid_len
,
state
.
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
state
.
iaid
,
opt6_ptr
(
ia_option
,
0
))))
lease_prune
(
lease
,
now
);
else
{
if
(
!
made_ia
)
{
o
=
new_opt6
(
ia_type
);
put_opt6_long
(
iaid
);
if
(
ia_type
==
OPTION6_IA_NA
)
o
=
new_opt6
(
state
.
ia_type
);
put_opt6_long
(
state
.
iaid
);
if
(
state
.
ia_type
==
OPTION6_IA_NA
)
{
put_opt6_long
(
0
);
put_opt6_long
(
0
);
...
...
@@ -1206,16 +1028,30 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
}
}
return
1
;
break
;
}
}
log_tags
(
tagif
,
state
.
xid
);
if
(
option_bool
(
OPT_LOG_OPTS
))
log6_opts
(
0
,
state
.
xid
,
daemon
->
outpacket
.
iov_base
+
start_opts
,
daemon
->
outpacket
.
iov_base
+
save_counter
(
-
1
));
return
1
;
}
struct
dhcp_netid
*
add_options
(
struct
state
*
state
,
struct
in6_addr
*
fallback
,
struct
dhcp_context
*
context
)
{
void
*
opt
,
*
oro
;
/* filter options based on tags, those we want get DHOPT_TAGOK bit set */
tagif
=
option_filter
(
tags
,
context_tags
,
daemon
->
dhcp_opts6
);
struct
dhcp_netid
*
tagif
=
option_filter
(
state
->
tags
,
state
->
context_tags
,
daemon
->
dhcp_opts6
);
struct
dhcp_opt
*
opt_cfg
;
int
done_dns
=
0
,
do_encap
=
0
;
int
i
,
o
,
o1
;
oro
=
opt6_find
(
packet_options
,
end
,
OPTION6_ORO
,
0
);
oro
=
opt6_find
(
state
->
packet_options
,
state
->
end
,
OPTION6_ORO
,
0
);
for
(
opt_cfg
=
daemon
->
dhcp_opts6
;
opt_cfg
;
opt_cfg
=
opt_cfg
->
next
)
{
...
...
@@ -1251,10 +1087,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
/* zero means "self" (but not in vendorclass options.) */
if
(
IN6_IS_ADDR_UNSPECIFIED
(
a
))
{
if
(
IN6_IS_ADDR_UNSPECIFIED
(
&
context
->
local6
))
if
(
!
add_local_addrs
(
context
))
put_opt6
(
fallback
,
IN6ADDRSZ
);
else
put_opt6
(
&
context
->
local6
,
IN6ADDRSZ
);
}
else
put_opt6
(
a
,
IN6ADDRSZ
);
...
...
@@ -1270,10 +1104,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
!
IN6_IS_ADDR_UNSPECIFIED
(
fallback
)))
{
o
=
new_opt6
(
OPTION6_DNS_SERVER
);
if
(
IN6_IS_ADDR_UNSPECIFIED
(
&
context
->
local6
))
if
(
!
add_local_addrs
(
context
))
put_opt6
(
fallback
,
IN6ADDRSZ
);
else
put_opt6
(
&
context
->
local6
,
IN6ADDRSZ
);
end_opt6
(
o
);
}
...
...
@@ -1334,21 +1166,21 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
}
if
(
hostname
)
if
(
state
->
hostname
)
{
unsigned
char
*
p
;
size_t
len
=
strlen
(
hostname
);
size_t
len
=
strlen
(
state
->
hostname
);
if
(
send_domain
)
len
+=
strlen
(
send_domain
)
+
1
;
if
(
s
tate
->
s
end_domain
)
len
+=
strlen
(
s
tate
->
s
end_domain
)
+
1
;
o
=
new_opt6
(
OPTION6_FQDN
);
if
((
p
=
expand
(
len
+
3
)))
{
*
(
p
++
)
=
fqdn_flags
;
p
=
do_rfc1035_name
(
p
,
hostname
);
if
(
send_domain
)
p
=
do_rfc1035_name
(
p
,
send_domain
);
*
(
p
++
)
=
state
->
fqdn_flags
;
p
=
do_rfc1035_name
(
p
,
state
->
hostname
);
if
(
s
tate
->
s
end_domain
)
p
=
do_rfc1035_name
(
p
,
s
tate
->
s
end_domain
);
*
p
=
0
;
}
end_opt6
(
o
);
...
...
@@ -1371,19 +1203,270 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if
(
i
>
opt6_len
(
oro
)
-
3
||
(
q
-
daemon
->
namebuff
)
>
40
)
{
q
=
daemon
->
namebuff
;
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"%u requested options: %s"
),
xid
,
daemon
->
namebuff
);
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"%u requested options: %s"
),
state
->
xid
,
daemon
->
namebuff
);
}
}
}
log_tags
(
tagif
,
xid
);
return
tagif
;
}
if
(
option_bool
(
OPT_LOG_OPTS
))
log6_opts
(
0
,
xid
,
daemon
->
outpacket
.
iov_base
+
start_opts
,
daemon
->
outpacket
.
iov_base
+
save_counter
(
-
1
));
static
int
add_local_addrs
(
struct
dhcp_context
*
context
)
{
int
done
=
0
;
return
1
;
for
(;
context
;
context
=
context
->
current
)
if
((
context
->
flags
&
CONTEXT_USED
)
&&
!
IN6_IS_ADDR_UNSPECIFIED
(
&
context
->
local6
))
{
/* squash duplicates */
struct
dhcp_context
*
c
;
for
(
c
=
context
->
current
;
c
;
c
=
c
->
current
)
if
((
c
->
flags
&
CONTEXT_USED
)
&&
IN6_ARE_ADDR_EQUAL
(
&
context
->
local6
,
&
c
->
local6
))
break
;
if
(
!
c
)
{
done
=
1
;
put_opt6
(
&
context
->
local6
,
IN6ADDRSZ
);
}
}
return
done
;
}
static
void
get_context_tag
(
struct
state
*
state
,
struct
dhcp_context
*
context
)
{
/* get tags from context if we've not used it before */
if
(
context
->
netid
.
next
==
&
context
->
netid
&&
context
->
netid
.
net
)
{
context
->
netid
.
next
=
state
->
context_tags
;
state
->
context_tags
=
&
context
->
netid
;
if
(
!
state
->
hostname_auth
)
{
struct
dhcp_netid_list
*
id_list
;
for
(
id_list
=
daemon
->
dhcp_ignore_names
;
id_list
;
id_list
=
id_list
->
next
)
if
((
!
id_list
->
list
)
||
match_netid
(
id_list
->
list
,
&
context
->
netid
,
0
))
break
;
if
(
id_list
)
state
->
hostname
=
NULL
;
}
}
}
static
void
*
check_ia
(
struct
state
*
state
,
void
*
opt
,
void
**
endp
)
{
state
->
ia_type
=
opt6_type
(
opt
);
if
(
state
->
ia_type
!=
OPTION6_IA_NA
&&
state
->
ia_type
!=
OPTION6_IA_TA
)
return
NULL
;
if
(
state
->
ia_type
==
OPTION6_IA_NA
&&
opt6_len
(
opt
)
<
12
)
return
NULL
;
if
(
state
->
ia_type
==
OPTION6_IA_TA
&&
opt6_len
(
opt
)
<
4
)
return
NULL
;
*
endp
=
opt6_ptr
(
opt
,
opt6_len
(
opt
));
state
->
iaid
=
opt6_uint
(
opt
,
0
,
4
);
return
opt6_find
(
opt6_ptr
(
opt
,
state
->
ia_type
==
OPTION6_IA_NA
?
12
:
4
),
*
endp
,
OPTION6_IAADDR
,
24
);
}
static
int
build_ia
(
struct
state
*
state
,
int
*
t1cntr
)
{
int
o
=
new_opt6
(
state
->
ia_type
);
put_opt6_long
(
state
->
iaid
);
*
t1cntr
=
0
;
if
(
state
->
ia_type
==
OPTION6_IA_NA
)
{
/* save pointer */
*
t1cntr
=
save_counter
(
-
1
);
/* so we can fill these in later */
put_opt6_long
(
0
);
put_opt6_long
(
0
);
}
return
o
;
}
static
void
end_ia
(
int
t1cntr
,
unsigned
int
min_time
,
int
do_fuzz
)
{
if
(
t1cntr
!=
0
)
{
/* go back an fill in fields in IA_NA option */
int
sav
=
save_counter
(
t1cntr
);
unsigned
int
t1
,
t2
,
fuzz
=
0
;
if
(
do_fuzz
)
{
fuzz
=
rand16
();
while
(
fuzz
>
(
min_time
/
16
))
fuzz
=
fuzz
/
2
;
}
t1
=
(
min_time
==
0xffffffff
)
?
0xffffffff
:
min_time
/
2
-
fuzz
;
t2
=
(
min_time
==
0xffffffff
)
?
0xffffffff
:
((
min_time
/
8
)
*
7
)
-
fuzz
;
put_opt6_long
(
t1
);
put_opt6_long
(
t2
);
save_counter
(
sav
);
}
}
static
void
add_address
(
struct
state
*
state
,
struct
dhcp_context
*
context
,
unsigned
int
lease_time
,
unsigned
int
requested_time
,
unsigned
int
*
min_time
,
struct
in6_addr
*
addr
,
int
do_update
,
time_t
now
)
{
unsigned
int
valid_time
=
(
context
->
valid
<
lease_time
)
?
context
->
valid
:
lease_time
;
int
o
=
new_opt6
(
OPTION6_IAADDR
);
struct
dhcp_lease
*
lease
;
put_opt6
(
addr
,
sizeof
(
*
addr
));
/* preferred lifetime */
if
(
requested_time
<
120u
)
requested_time
=
120u
;
/* sanity */
if
(
lease_time
==
0xffffffff
||
(
requested_time
!=
0xffffffff
&&
requested_time
<
lease_time
))
lease_time
=
requested_time
;
if
(
lease_time
<
*
min_time
)
*
min_time
=
lease_time
;
put_opt6_long
((
context
->
preferred
<
lease_time
)
?
context
->
preferred
:
lease_time
);
put_opt6_long
(
valid_time
);
/* valid lifetime */
end_opt6
(
o
);
if
(
do_update
)
update_leases
(
state
,
context
,
addr
,
valid_time
,
now
);
if
((
lease
=
lease6_find_by_addr
(
addr
,
128
,
0
)))
lease
->
flags
|=
LEASE_USED
;
/* get tags from context if we've not used it before */
if
(
context
->
netid
.
next
==
&
context
->
netid
&&
context
->
netid
.
net
)
{
context
->
netid
.
next
=
state
->
context_tags
;
state
->
context_tags
=
&
context
->
netid
;
if
(
!
state
->
hostname_auth
)
{
struct
dhcp_netid_list
*
id_list
;
for
(
id_list
=
daemon
->
dhcp_ignore_names
;
id_list
;
id_list
=
id_list
->
next
)
if
((
!
id_list
->
list
)
||
match_netid
(
id_list
->
list
,
&
context
->
netid
,
0
))
break
;
if
(
id_list
)
state
->
hostname
=
NULL
;
}
}
/* Mark that we have an address for this prefix. */
for
(
context
=
state
->
context
;
context
;
context
=
context
->
current
)
if
(
is_same_net6
(
addr
,
&
context
->
start6
,
context
->
prefix
))
context
->
flags
|=
CONTEXT_USED
;
log6_packet
(
state
,
do_update
?
"DHCPREPLY"
:
"DHCPADVERTISE"
,
addr
,
state
->
hostname
);
}
static
void
update_leases
(
struct
state
*
state
,
struct
dhcp_context
*
context
,
struct
in6_addr
*
addr
,
unsigned
int
lease_time
,
time_t
now
)
{
struct
dhcp_lease
*
lease
=
lease6_find_by_addr
(
addr
,
128
,
0
);
struct
dhcp_netid
*
tagif
=
run_tag_if
(
state
->
tags
);
if
(
!
lease
)
lease
=
lease6_allocate
(
addr
,
state
->
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
);
if
(
lease
)
{
lease_set_expires
(
lease
,
lease_time
,
now
);
lease_set_hwaddr
(
lease
,
NULL
,
state
->
clid
,
0
,
state
->
iaid
,
state
->
clid_len
,
now
,
0
);
lease_set_interface
(
lease
,
state
->
interface
,
now
);
if
(
state
->
hostname
&&
state
->
ia_type
==
OPTION6_IA_NA
)
{
char
*
addr_domain
=
get_domain6
(
addr
);
if
(
!
state
->
send_domain
)
state
->
send_domain
=
addr_domain
;
lease_set_hostname
(
lease
,
state
->
hostname
,
state
->
hostname_auth
,
addr_domain
,
state
->
domain
);
}
#ifdef HAVE_SCRIPT
if
(
daemon
->
lease_change_command
)
{
void
*
class_opt
;
lease
->
flags
|=
LEASE_CHANGED
;
free
(
lease
->
extradata
);
lease
->
extradata
=
NULL
;
lease
->
extradata_size
=
lease
->
extradata_len
=
0
;
lease
->
hwaddr_len
=
0
;
/* surrogate for no of vendor classes */
if
((
class_opt
=
opt6_find
(
state
->
packet_options
,
state
->
end
,
OPTION6_VENDOR_CLASS
,
4
)))
{
void
*
enc_opt
,
*
enc_end
=
opt6_ptr
(
class_opt
,
opt6_len
(
class_opt
));
lease
->
hwaddr_len
++
;
/* send enterprise number first */
sprintf
(
daemon
->
dhcp_buff2
,
"%u"
,
opt6_uint
(
class_opt
,
0
,
4
));
lease_add_extradata
(
lease
,
(
unsigned
char
*
)
daemon
->
dhcp_buff2
,
strlen
(
daemon
->
dhcp_buff2
),
0
);
if
(
opt6_len
(
class_opt
)
>=
6
)
for
(
enc_opt
=
opt6_ptr
(
class_opt
,
4
);
enc_opt
;
enc_opt
=
opt6_next
(
enc_opt
,
enc_end
))
{
lease
->
hwaddr_len
++
;
lease_add_extradata
(
lease
,
opt6_ptr
(
enc_opt
,
0
),
opt6_len
(
enc_opt
),
0
);
}
}
lease_add_extradata
(
lease
,
(
unsigned
char
*
)
state
->
client_hostname
,
state
->
client_hostname
?
strlen
(
state
->
client_hostname
)
:
0
,
0
);
/* space-concat tag set */
if
(
!
tagif
&&
!
context
->
netid
.
net
)
lease_add_extradata
(
lease
,
NULL
,
0
,
0
);
else
{
if
(
context
->
netid
.
net
)
lease_add_extradata
(
lease
,
(
unsigned
char
*
)
context
->
netid
.
net
,
strlen
(
context
->
netid
.
net
),
tagif
?
' '
:
0
);
if
(
tagif
)
{
struct
dhcp_netid
*
n
;
for
(
n
=
tagif
;
n
;
n
=
n
->
next
)
{
struct
dhcp_netid
*
n1
;
/* kill dupes */
for
(
n1
=
n
->
next
;
n1
;
n1
=
n1
->
next
)
if
(
strcmp
(
n
->
net
,
n1
->
net
)
==
0
)
break
;
if
(
!
n1
)
lease_add_extradata
(
lease
,
(
unsigned
char
*
)
n
->
net
,
strlen
(
n
->
net
),
n
->
next
?
' '
:
0
);
}
}
}
if
(
state
->
link_address
)
inet_ntop
(
AF_INET6
,
state
->
link_address
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
lease_add_extradata
(
lease
,
(
unsigned
char
*
)
daemon
->
addrbuff
,
state
->
link_address
?
strlen
(
daemon
->
addrbuff
)
:
0
,
0
);
if
((
class_opt
=
opt6_find
(
state
->
packet_options
,
state
->
end
,
OPTION6_USER_CLASS
,
2
)))
{
void
*
enc_opt
,
*
enc_end
=
opt6_ptr
(
class_opt
,
opt6_len
(
class_opt
));
for
(
enc_opt
=
opt6_ptr
(
class_opt
,
0
);
enc_opt
;
enc_opt
=
opt6_next
(
enc_opt
,
enc_end
))
lease_add_extradata
(
lease
,
opt6_ptr
(
enc_opt
,
0
),
opt6_len
(
enc_opt
),
0
);
}
}
#endif
}
}
static
void
log6_opts
(
int
nest
,
unsigned
int
xid
,
void
*
start_opts
,
void
*
end_opts
)
{
void
*
opt
;
...
...
@@ -1441,13 +1524,15 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op
}
}
static
void
log6_packet
(
char
*
type
,
unsigned
char
*
clid
,
int
clid_len
,
struct
in6_addr
*
addr
,
int
xid
,
char
*
iface
,
char
*
string
)
static
void
log6_packet
(
struct
state
*
state
,
char
*
type
,
struct
in6_addr
*
addr
,
char
*
string
)
{
int
clid_len
=
state
->
clid_len
;
/* avoid buffer overflow */
if
(
clid_len
>
100
)
clid_len
=
100
;
print_mac
(
daemon
->
namebuff
,
clid
,
clid_len
);
print_mac
(
daemon
->
namebuff
,
state
->
clid
,
clid_len
);
if
(
addr
)
{
...
...
@@ -1459,16 +1544,16 @@ static void log6_packet(char *type, unsigned char *clid, int clid_len, struct in
if
(
option_bool
(
OPT_LOG_OPTS
))
my_syslog
(
MS_DHCP
|
LOG_INFO
,
"%u %s(%s) %s%s %s"
,
xid
,
state
->
xid
,
type
,
ifac
e
,
state
->
iface_nam
e
,
daemon
->
dhcp_buff2
,
daemon
->
namebuff
,
string
?
string
:
""
);
else
my_syslog
(
MS_DHCP
|
LOG_INFO
,
"%s(%s) %s%s %s"
,
type
,
ifac
e
,
state
->
iface_nam
e
,
daemon
->
dhcp_buff2
,
daemon
->
namebuff
,
string
?
string
:
""
);
...
...
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