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
c6cc03ed
Commit
c6cc03ed
authored
Feb 10, 2012
by
Simon Kelley
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dhcpv6'
parents
751d6f4a
3d7b550f
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
2796 additions
and
986 deletions
+2796
-986
Makefile
Makefile
+3
-3
bld/Android.mk
bld/Android.mk
+2
-1
src/NOTES
src/NOTES
+0
-15
src/bpf.c
src/bpf.c
+19
-1
src/cache.c
src/cache.c
+51
-18
src/config.h
src/config.h
+1
-1
src/dhcp-common.c
src/dhcp-common.c
+361
-0
src/dhcp.c
src/dhcp.c
+1
-175
src/dhcp6.c
src/dhcp6.c
+179
-21
src/dhcp6_protocol.h
src/dhcp6_protocol.h
+4
-1
src/dnsmasq.c
src/dnsmasq.c
+3
-1
src/dnsmasq.h
src/dnsmasq.h
+57
-24
src/helper.c
src/helper.c
+141
-39
src/lease.c
src/lease.c
+200
-112
src/netlink.c
src/netlink.c
+3
-1
src/option.c
src/option.c
+458
-63
src/rfc2131.c
src/rfc2131.c
+33
-202
src/rfc3315.c
src/rfc3315.c
+1280
-308
No files found.
Makefile
View file @
c6cc03ed
...
@@ -45,7 +45,7 @@ VERSION= -DVERSION='\"`../bld/get-version`\"'
...
@@ -45,7 +45,7 @@ VERSION= -DVERSION='\"`../bld/get-version`\"'
OBJS
=
cache.o rfc1035.o util.o option.o forward.o network.o
\
OBJS
=
cache.o rfc1035.o util.o option.o forward.o network.o
\
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o
\
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o
\
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o
dhcp-common.o
all
:
all
:
@
cd
$(SRC)
&&
$(MAKE)
\
@
cd
$(SRC)
&&
$(MAKE)
\
...
@@ -88,10 +88,10 @@ merge :
...
@@ -88,10 +88,10 @@ merge :
# rules below are targets in recusive makes with cwd=$(SRC)
# rules below are targets in recusive makes with cwd=$(SRC)
.c.o
:
.c.o
:
$(CC)
$(CFLAGS)
$(COPTS)
$(I18N)
$(BUILD_CFLAGS)
$(RPM_OPT_FLAGS)
-c
$<
$(CC)
$(CFLAGS)
$(COPTS)
$(I18N)
$(BUILD_CFLAGS)
$(RPM_OPT_FLAGS)
-c
$<
dnsmasq
:
$(OBJS)
dnsmasq
:
$(OBJS)
$(CC)
$(LDFLAGS)
-o
$@
$(OBJS)
$(BUILD_LIBS)
$(LIBS)
$(CC)
$(LDFLAGS)
-o
$@
$(OBJS)
$(BUILD_LIBS)
$(LIBS)
dnsmasq.pot
:
$(OBJS:.o=.c) dnsmasq.h config.h
dnsmasq.pot
:
$(OBJS:.o=.c) dnsmasq.h config.h
...
...
bld/Android.mk
View file @
c6cc03ed
...
@@ -6,7 +6,8 @@ include $(CLEAR_VARS)
...
@@ -6,7 +6,8 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES
:=
bpf.c cache.c dbus.c dhcp.c dnsmasq.c
\
LOCAL_SRC_FILES
:=
bpf.c cache.c dbus.c dhcp.c dnsmasq.c
\
forward.c helper.c lease.c log.c
\
forward.c helper.c lease.c log.c
\
netlink.c network.c option.c rfc1035.c
\
netlink.c network.c option.c rfc1035.c
\
rfc2131.c tftp.c util.c conntrack.c
rfc2131.c tftp.c util.c conntrack.c
\
dhcp6.c rfc3315.c dhcp-common.c
LOCAL_MODULE
:=
dnsmasq
LOCAL_MODULE
:=
dnsmasq
...
...
src/NOTES
deleted
100644 → 0
View file @
751d6f4a
Worry about IPv6 leases and DUID in script-storage.
dhcpv6-range
dhcpv6-option
dhcpv6-option-force
dhcpv6-script ?
dhcpv6-optsfile
dhcpv6-hostsfile
dhcp-host =
[<hwaddr>][,id:<client_id>|*][,net:<netid>][,<ipv4addr>][\[ipv6addr\]][,<hostname>][,<lease_time>][,ignore]
IPv6 address like [2001:db8:do::2]
src/bpf.c
View file @
c6cc03ed
...
@@ -153,7 +153,25 @@ int iface_enumerate(int family, void *parm, int (*callback)())
...
@@ -153,7 +153,25 @@ int iface_enumerate(int family, void *parm, int (*callback)())
ifr
=
(
struct
ifreq
*
)
ifreq
.
iov_base
;
ifr
=
(
struct
ifreq
*
)
ifreq
.
iov_base
;
memcpy
(
ifr
,
ptr
,
len
);
memcpy
(
ifr
,
ptr
,
len
);
#ifdef HAVE_DHCP6
if
(
family
==
AF_LOCAL
)
{
unsigned
int
flags
;
if
(
ioctl
(
fd
,
SIOCGIFFLAGS
,
ifr
)
!=
-
1
)
{
flags
=
ifr
.
ifr_flags
;
ifr
->
ifr_addr
.
sa_family
=
AF_LINK
;
if
(
ioctl
(
fd
,
SIOCGIFADDR
,
ifr
)
!=
-
1
&&
!
((
*
callback
)((
unsigned
int
)
htons
(
ETHERTYPE_IP
),
(
unsigned
int
)
link
->
ifi_flags
,
LLADDR
((
struct
sockaddr_dl
*
)
&
ifr
->
ifr_addr
),
ETHER_ADDR_LEN
,
parm
)))
goto
err
;
}
continue
;
}
#endif
if
(
ifr
->
ifr_addr
.
sa_family
==
family
)
if
(
ifr
->
ifr_addr
.
sa_family
==
family
)
{
{
if
(
family
==
AF_INET
)
if
(
family
==
AF_INET
)
...
...
src/cache.c
View file @
c6cc03ed
...
@@ -782,7 +782,7 @@ static int read_hostsfile(char *filename, int index, int cache_size, struct crec
...
@@ -782,7 +782,7 @@ static int read_hostsfile(char *filename, int index, int cache_size, struct crec
{
{
flags
=
F_HOSTS
|
F_IMMORTAL
|
F_FORWARD
|
F_REVERSE
|
F_IPV6
;
flags
=
F_HOSTS
|
F_IMMORTAL
|
F_FORWARD
|
F_REVERSE
|
F_IPV6
;
addrlen
=
IN6ADDRSZ
;
addrlen
=
IN6ADDRSZ
;
domain_suffix
=
daemon
->
domain_suffix
;
domain_suffix
=
get_domain6
(
&
addr
.
addr
.
addr6
)
;
}
}
#else
#else
if
((
addr
.
addr
.
addr4
.
s_addr
=
inet_addr
(
token
))
!=
(
in_addr_t
)
-
1
)
if
((
addr
.
addr
.
addr4
.
s_addr
=
inet_addr
(
token
))
!=
(
in_addr_t
)
-
1
)
...
@@ -913,13 +913,33 @@ char *get_domain(struct in_addr addr)
...
@@ -913,13 +913,33 @@ char *get_domain(struct in_addr addr)
struct
cond_domain
*
c
;
struct
cond_domain
*
c
;
for
(
c
=
daemon
->
cond_domain
;
c
;
c
=
c
->
next
)
for
(
c
=
daemon
->
cond_domain
;
c
;
c
=
c
->
next
)
if
(
ntohl
(
addr
.
s_addr
)
>=
ntohl
(
c
->
start
.
s_addr
)
&&
if
(
!
c
->
is6
&&
ntohl
(
addr
.
s_addr
)
>=
ntohl
(
c
->
start
.
s_addr
)
&&
ntohl
(
addr
.
s_addr
)
<=
ntohl
(
c
->
end
.
s_addr
))
ntohl
(
addr
.
s_addr
)
<=
ntohl
(
c
->
end
.
s_addr
))
return
c
->
domain
;
return
c
->
domain
;
return
daemon
->
domain_suffix
;
return
daemon
->
domain_suffix
;
}
}
#ifdef HAVE_IPV6
char
*
get_domain6
(
struct
in6_addr
*
addr
)
{
struct
cond_domain
*
c
;
u64
addrpart
=
addr6part
(
addr
);
for
(
c
=
daemon
->
cond_domain
;
c
;
c
=
c
->
next
)
if
(
c
->
is6
&&
is_same_net6
(
addr
,
&
c
->
start6
,
64
)
&&
addrpart
>=
addr6part
(
&
c
->
start6
)
&&
addrpart
<=
addr6part
(
&
c
->
end6
))
return
c
->
domain
;
return
daemon
->
domain_suffix
;
}
#endif
#ifdef HAVE_DHCP
#ifdef HAVE_DHCP
struct
in_addr
a_record_from_hosts
(
char
*
name
,
time_t
now
)
struct
in_addr
a_record_from_hosts
(
char
*
name
,
time_t
now
)
{
{
...
@@ -953,15 +973,24 @@ void cache_unhash_dhcp(void)
...
@@ -953,15 +973,24 @@ void cache_unhash_dhcp(void)
up
=
&
cache
->
hash_next
;
up
=
&
cache
->
hash_next
;
}
}
void
cache_add_dhcp_entry
(
char
*
host_name
,
void
cache_add_dhcp_entry
(
char
*
host_name
,
int
prot
,
struct
in
_addr
*
host_address
,
time_t
ttd
)
struct
all
_addr
*
host_address
,
time_t
ttd
)
{
{
struct
crec
*
crec
=
NULL
,
*
aliasc
;
struct
crec
*
crec
=
NULL
,
*
aliasc
;
unsigned
short
flags
=
F_NAMEP
|
F_DHCP
|
F_FORWARD
|
F_IPV4
|
F_REVERSE
;
unsigned
short
flags
=
F_IPV4
;
int
in_hosts
=
0
;
int
in_hosts
=
0
;
struct
cname
*
a
;
struct
cname
*
a
;
size_t
addrlen
=
sizeof
(
struct
in_addr
);
#ifdef HAVE_IPV6
if
(
prot
==
AF_INET6
)
{
flags
=
F_IPV6
;
addrlen
=
sizeof
(
struct
in6_addr
);
}
#endif
while
((
crec
=
cache_find_by_name
(
crec
,
host_name
,
0
,
F_IPV4
|
F_CNAME
)))
while
((
crec
=
cache_find_by_name
(
crec
,
host_name
,
0
,
flags
|
F_CNAME
)))
{
{
/* check all addresses associated with name */
/* check all addresses associated with name */
if
(
crec
->
flags
&
F_HOSTS
)
if
(
crec
->
flags
&
F_HOSTS
)
...
@@ -969,23 +998,25 @@ void cache_add_dhcp_entry(char *host_name,
...
@@ -969,23 +998,25 @@ void cache_add_dhcp_entry(char *host_name,
/* if in hosts, don't need DHCP record */
/* if in hosts, don't need DHCP record */
in_hosts
=
1
;
in_hosts
=
1
;
inet_ntop
(
prot
,
host_address
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
if
(
crec
->
flags
&
F_CNAME
)
if
(
crec
->
flags
&
F_CNAME
)
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"%s is a CNAME, not giving it to the DHCP lease of %s"
),
_
(
"%s is a CNAME, not giving it to the DHCP lease of %s"
),
host_name
,
inet_ntoa
(
*
host_address
)
);
host_name
,
daemon
->
addrbuff
);
else
if
(
crec
->
addr
.
addr
.
addr
.
addr4
.
s_addr
!=
host_address
->
s_addr
)
else
if
(
memcmp
(
&
crec
->
addr
.
addr
,
host_address
,
addrlen
)
!=
0
)
{
{
strcpy
(
daemon
->
namebuff
,
inet_ntoa
(
crec
->
addr
.
addr
.
addr
.
addr4
)
);
inet_ntop
(
prot
,
&
crec
->
addr
.
addr
,
daemon
->
namebuff
,
MAXDNAME
);
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"not giving name %s to the DHCP lease of %s because "
_
(
"not giving name %s to the DHCP lease of %s because "
"the name exists in %s with address %s"
),
"the name exists in %s with address %s"
),
host_name
,
inet_ntoa
(
*
host_address
)
,
host_name
,
daemon
->
addrbuff
,
record_source
(
crec
->
uid
),
daemon
->
namebuff
);
record_source
(
crec
->
uid
),
daemon
->
namebuff
);
}
}
}
}
else
if
(
!
(
crec
->
flags
&
F_DHCP
))
else
if
(
!
(
crec
->
flags
&
F_DHCP
))
{
{
cache_scan_free
(
host_name
,
NULL
,
0
,
crec
->
flags
&
(
F_IPV4
|
F_CNAME
|
F_FORWARD
));
cache_scan_free
(
host_name
,
NULL
,
0
,
crec
->
flags
&
(
flags
|
F_CNAME
|
F_FORWARD
));
/* scan_free deletes all addresses associated with name */
/* scan_free deletes all addresses associated with name */
break
;
break
;
}
}
...
@@ -994,14 +1025,16 @@ void cache_add_dhcp_entry(char *host_name,
...
@@ -994,14 +1025,16 @@ void cache_add_dhcp_entry(char *host_name,
if
(
in_hosts
)
if
(
in_hosts
)
return
;
return
;
if
((
crec
=
cache_find_by_addr
(
NULL
,
(
struct
all_addr
*
)
host_address
,
0
,
F_IPV4
)))
if
((
crec
=
cache_find_by_addr
(
NULL
,
(
struct
all_addr
*
)
host_address
,
0
,
flags
)))
{
{
if
(
crec
->
flags
&
F_NEG
)
if
(
crec
->
flags
&
F_NEG
)
cache_scan_free
(
NULL
,
(
struct
all_addr
*
)
host_address
,
0
,
F_IPV4
|
F_REVERSE
);
{
else
flags
|=
F_REVERSE
;
/* avoid multiple reverse mappings */
cache_scan_free
(
NULL
,
(
struct
all_addr
*
)
host_address
,
0
,
flags
);
flags
&=
~
F_REVERSE
;
}
}
}
else
flags
|=
F_REVERSE
;
if
((
crec
=
dhcp_spare
))
if
((
crec
=
dhcp_spare
))
dhcp_spare
=
dhcp_spare
->
next
;
dhcp_spare
=
dhcp_spare
->
next
;
...
@@ -1010,12 +1043,12 @@ void cache_add_dhcp_entry(char *host_name,
...
@@ -1010,12 +1043,12 @@ void cache_add_dhcp_entry(char *host_name,
if
(
crec
)
/* malloc may fail */
if
(
crec
)
/* malloc may fail */
{
{
crec
->
flags
=
flags
;
crec
->
flags
=
flags
|
F_NAMEP
|
F_DHCP
|
F_FORWARD
;
if
(
ttd
==
0
)
if
(
ttd
==
0
)
crec
->
flags
|=
F_IMMORTAL
;
crec
->
flags
|=
F_IMMORTAL
;
else
else
crec
->
ttd
=
ttd
;
crec
->
ttd
=
ttd
;
crec
->
addr
.
addr
.
addr
.
addr4
=
*
host_address
;
crec
->
addr
.
addr
=
*
host_address
;
crec
->
name
.
namep
=
host_name
;
crec
->
name
.
namep
=
host_name
;
crec
->
uid
=
uid
++
;
crec
->
uid
=
uid
++
;
cache_hash
(
crec
);
cache_hash
(
crec
);
...
...
src/config.h
View file @
c6cc03ed
...
@@ -116,7 +116,7 @@ RESOLVFILE
...
@@ -116,7 +116,7 @@ RESOLVFILE
has no library dependencies other than libc */
has no library dependencies other than libc */
#define HAVE_DHCP
#define HAVE_DHCP
/* #define HAVE_DHCP6 */
#define HAVE_DHCP6
#define HAVE_TFTP
#define HAVE_TFTP
#define HAVE_SCRIPT
#define HAVE_SCRIPT
/* #define HAVE_LUASCRIPT */
/* #define HAVE_LUASCRIPT */
...
...
src/dhcp-common.c
0 → 100644
View file @
c6cc03ed
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#ifdef HAVE_DHCP
void
dhcp_common_init
(
void
)
{
/* These each hold a DHCP option max size 255
and get a terminating zero added */
daemon
->
dhcp_buff
=
safe_malloc
(
256
);
daemon
->
dhcp_buff2
=
safe_malloc
(
256
);
daemon
->
dhcp_buff3
=
safe_malloc
(
256
);
/* dhcp_packet is used by v4 and v6, outpacket only by v6
sizeof(struct dhcp_packet) is as good an initial size as any,
even for v6 */
expand_buf
(
&
daemon
->
dhcp_packet
,
sizeof
(
struct
dhcp_packet
));
#ifdef HAVE_DHCP6
if
(
daemon
->
dhcp6
)
expand_buf
(
&
daemon
->
outpacket
,
sizeof
(
struct
dhcp_packet
));
#endif
}
ssize_t
recv_dhcp_packet
(
int
fd
,
struct
msghdr
*
msg
)
{
ssize_t
sz
;
while
(
1
)
{
msg
->
msg_flags
=
0
;
while
((
sz
=
recvmsg
(
fd
,
msg
,
MSG_PEEK
|
MSG_TRUNC
))
==
-
1
&&
errno
==
EINTR
);
if
(
sz
==
-
1
)
return
-
1
;
if
(
!
(
msg
->
msg_flags
&
MSG_TRUNC
))
break
;
/* Very new Linux kernels return the actual size needed,
older ones always return truncated size */
if
((
size_t
)
sz
==
daemon
->
dhcp_packet
.
iov_len
)
{
if
(
!
expand_buf
(
&
daemon
->
dhcp_packet
,
sz
+
100
))
return
-
1
;
}
else
{
expand_buf
(
&
daemon
->
dhcp_packet
,
sz
);
break
;
}
}
while
((
sz
=
recvmsg
(
fd
,
msg
,
0
))
==
-
1
&&
errno
==
EINTR
);
return
(
msg
->
msg_flags
&
MSG_TRUNC
)
?
-
1
:
sz
;
}
struct
dhcp_netid
*
run_tag_if
(
struct
dhcp_netid
*
tags
)
{
struct
tag_if
*
exprs
;
struct
dhcp_netid_list
*
list
;
for
(
exprs
=
daemon
->
tag_if
;
exprs
;
exprs
=
exprs
->
next
)
if
(
match_netid
(
exprs
->
tag
,
tags
,
1
))
for
(
list
=
exprs
->
set
;
list
;
list
=
list
->
next
)
{
list
->
list
->
next
=
tags
;
tags
=
list
->
list
;
}
return
tags
;
}
struct
dhcp_netid
*
option_filter
(
struct
dhcp_netid
*
tags
,
struct
dhcp_netid
*
context_tags
,
struct
dhcp_opt
*
opts
)
{
struct
dhcp_netid
*
tagif
=
run_tag_if
(
tags
);
struct
dhcp_opt
*
opt
;
/* flag options which are valid with the current tag set (sans context tags) */
for
(
opt
=
opts
;
opt
;
opt
=
opt
->
next
)
{
opt
->
flags
&=
~
DHOPT_TAGOK
;
if
(
!
(
opt
->
flags
&
(
DHOPT_ENCAPSULATE
|
DHOPT_VENDOR
|
DHOPT_RFC3925
))
&&
match_netid
(
opt
->
netid
,
tagif
,
0
))
opt
->
flags
|=
DHOPT_TAGOK
;
}
/* now flag options which are valid, including the context tags,
otherwise valid options are inhibited if we found a higher priotity one above */
if
(
context_tags
)
{
struct
dhcp_netid
*
last_tag
;
for
(
last_tag
=
context_tags
;
last_tag
->
next
;
last_tag
=
last_tag
->
next
);
last_tag
->
next
=
tags
;
tagif
=
run_tag_if
(
context_tags
);
for
(
opt
=
opts
;
opt
;
opt
=
opt
->
next
)
if
(
!
(
opt
->
flags
&
(
DHOPT_ENCAPSULATE
|
DHOPT_VENDOR
|
DHOPT_RFC3925
|
DHOPT_TAGOK
))
&&
match_netid
(
opt
->
netid
,
tagif
,
0
))
{
struct
dhcp_opt
*
tmp
;
for
(
tmp
=
opts
;
tmp
;
tmp
=
tmp
->
next
)
if
(
tmp
->
opt
==
opt
->
opt
&&
opt
->
netid
&&
(
tmp
->
flags
&
DHOPT_TAGOK
))
break
;
if
(
!
tmp
)
opt
->
flags
|=
DHOPT_TAGOK
;
}
}
/* now flag untagged options which are not overridden by tagged ones */
for
(
opt
=
opts
;
opt
;
opt
=
opt
->
next
)
if
(
!
(
opt
->
flags
&
(
DHOPT_ENCAPSULATE
|
DHOPT_VENDOR
|
DHOPT_RFC3925
|
DHOPT_TAGOK
))
&&
!
opt
->
netid
)
{
struct
dhcp_opt
*
tmp
;
for
(
tmp
=
opts
;
tmp
;
tmp
=
tmp
->
next
)
if
(
tmp
->
opt
==
opt
->
opt
&&
(
tmp
->
flags
&
DHOPT_TAGOK
))
break
;
if
(
!
tmp
)
opt
->
flags
|=
DHOPT_TAGOK
;
else
if
(
!
tmp
->
netid
)
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"Ignoring duplicate dhcp-option %d"
),
tmp
->
opt
);
}
return
tagif
;
}
/* Is every member of check matched by a member of pool?
If tagnotneeded, untagged is OK */
int
match_netid
(
struct
dhcp_netid
*
check
,
struct
dhcp_netid
*
pool
,
int
tagnotneeded
)
{
struct
dhcp_netid
*
tmp1
;
if
(
!
check
&&
!
tagnotneeded
)
return
0
;
for
(;
check
;
check
=
check
->
next
)
{
/* '#' for not is for backwards compat. */
if
(
check
->
net
[
0
]
!=
'!'
&&
check
->
net
[
0
]
!=
'#'
)
{
for
(
tmp1
=
pool
;
tmp1
;
tmp1
=
tmp1
->
next
)
if
(
strcmp
(
check
->
net
,
tmp1
->
net
)
==
0
)
break
;
if
(
!
tmp1
)
return
0
;
}
else
for
(
tmp1
=
pool
;
tmp1
;
tmp1
=
tmp1
->
next
)
if
(
strcmp
((
check
->
net
)
+
1
,
tmp1
->
net
)
==
0
)
return
0
;
}
return
1
;
}
/* return domain or NULL if none. */
char
*
strip_hostname
(
char
*
hostname
)
{
char
*
dot
=
strchr
(
hostname
,
'.'
);
if
(
!
dot
)
return
NULL
;
*
dot
=
0
;
/* truncate */
if
(
strlen
(
dot
+
1
)
!=
0
)
return
dot
+
1
;
return
NULL
;
}
void
log_tags
(
struct
dhcp_netid
*
netid
,
u32
xid
)
{
if
(
netid
&&
option_bool
(
OPT_LOG_OPTS
))
{
char
*
s
=
daemon
->
namebuff
;
for
(
*
s
=
0
;
netid
;
netid
=
netid
->
next
)
{
/* kill dupes. */
struct
dhcp_netid
*
n
;
for
(
n
=
netid
->
next
;
n
;
n
=
n
->
next
)
if
(
strcmp
(
netid
->
net
,
n
->
net
)
==
0
)
break
;
if
(
!
n
)
{
strncat
(
s
,
netid
->
net
,
(
MAXDNAME
-
1
)
-
strlen
(
s
));
if
(
netid
->
next
)
strncat
(
s
,
", "
,
(
MAXDNAME
-
1
)
-
strlen
(
s
));
}
}
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"%u tags: %s"
),
xid
,
s
);
}
}
int
match_bytes
(
struct
dhcp_opt
*
o
,
unsigned
char
*
p
,
int
len
)
{
int
i
;
if
(
o
->
len
>
len
)
return
0
;
if
(
o
->
len
==
0
)
return
1
;
if
(
o
->
flags
&
DHOPT_HEX
)
{
if
(
memcmp_masked
(
o
->
val
,
p
,
o
->
len
,
o
->
u
.
wildcard_mask
))
return
1
;
}
else
for
(
i
=
0
;
i
<=
(
len
-
o
->
len
);
)
{
if
(
memcmp
(
o
->
val
,
p
+
i
,
o
->
len
)
==
0
)
return
1
;
if
(
o
->
flags
&
DHOPT_STRING
)
i
++
;
else
i
+=
o
->
len
;
}
return
0
;
}
void
check_dhcp_hosts
(
int
fatal
)
{
/* If the same IP appears in more than one host config, then DISCOVER
for one of the hosts will get the address, but REQUEST will be NAKed,
since the address is reserved by the other one -> protocol loop.
Also check that FQDNs match the domain we are using. */
struct
dhcp_config
*
configs
,
*
cp
;
for
(
configs
=
daemon
->
dhcp_conf
;
configs
;
configs
=
configs
->
next
)
{
char
*
domain
;
if
((
configs
->
flags
&
DHOPT_BANK
)
||
fatal
)
{
for
(
cp
=
configs
->
next
;
cp
;
cp
=
cp
->
next
)
if
((
configs
->
flags
&
cp
->
flags
&
CONFIG_ADDR
)
&&
configs
->
addr
.
s_addr
==
cp
->
addr
.
s_addr
)
{
if
(
fatal
)
die
(
_
(
"duplicate IP address %s in dhcp-config directive."
),
inet_ntoa
(
cp
->
addr
),
EC_BADCONF
);
else
my_syslog
(
MS_DHCP
|
LOG_ERR
,
_
(
"duplicate IP address %s in %s."
),
inet_ntoa
(
cp
->
addr
),
daemon
->
dhcp_hosts_file
);
configs
->
flags
&=
~
CONFIG_ADDR
;
}
/* split off domain part */
if
((
configs
->
flags
&
CONFIG_NAME
)
&&
(
domain
=
strip_hostname
(
configs
->
hostname
)))
configs
->
domain
=
domain
;
}
}
}
void
dhcp_update_configs
(
struct
dhcp_config
*
configs
)
{
/* Some people like to keep all static IP addresses in /etc/hosts.
This goes through /etc/hosts and sets static addresses for any DHCP config
records which don't have an address and whose name matches.
We take care to maintain the invariant that any IP address can appear
in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
restore the status-quo ante first. */
struct
dhcp_config
*
config
;
struct
crec
*
crec
;
int
prot
=
AF_INET
;
for
(
config
=
configs
;
config
;
config
=
config
->
next
)
if
(
config
->
flags
&
CONFIG_ADDR_HOSTS
)
config
->
flags
&=
~
(
CONFIG_ADDR
|
CONFIG_ADDR6
|
CONFIG_ADDR_HOSTS
);
#ifdef HAVE_DHCP6
again:
#endif
if
(
daemon
->
port
!=
0
)
for
(
config
=
configs
;
config
;
config
=
config
->
next
)
{
int
conflags
=
CONFIG_ADDR
;
int
cacheflags
=
F_IPV4
;
#ifdef HAVE_DHCP6
if
(
prot
==
AF_INET6
)
{
conflags
=
CONFIG_ADDR6
;
cacheflags
=
F_IPV6
;
}
#endif
if
(
!
(
config
->
flags
&
conflags
)
&&
(
config
->
flags
&
CONFIG_NAME
)
&&
(
crec
=
cache_find_by_name
(
NULL
,
config
->
hostname
,
0
,
cacheflags
))
&&
(
crec
->
flags
&
F_HOSTS
))
{
if
(
cache_find_by_name
(
crec
,
config
->
hostname
,
0
,
cacheflags
))
{
/* use primary (first) address */
while
(
crec
&&
!
(
crec
->
flags
&
F_REVERSE
))
crec
=
cache_find_by_name
(
crec
,
config
->
hostname
,
0
,
cacheflags
);
if
(
!
crec
)
continue
;
/* should be never */
inet_ntop
(
prot
,
&
crec
->
addr
.
addr
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"%s has more than one address in hostsfile, using %s for DHCP"
),
config
->
hostname
,
daemon
->
addrbuff
);
}
if
(
prot
==
AF_INET
&&
!
config_find_by_address
(
configs
,
crec
->
addr
.
addr
.
addr
.
addr4
))
{
config
->
addr
=
crec
->
addr
.
addr
.
addr
.
addr4
;
config
->
flags
|=
CONFIG_ADDR
|
CONFIG_ADDR_HOSTS
;
continue
;
}
#ifdef HAVE_DHCP6
if
(
prot
==
AF_INET6
&&
!
config_find_by_address6
(
configs
,
&
crec
->
addr
.
addr
.
addr
.
addr6
,
129
,
0
))
{
memcpy
(
config
->
hwaddr
,
&
crec
->
addr
.
addr
.
addr
.
addr6
,
IN6ADDRSZ
);
config
->
flags
|=
CONFIG_ADDR6
|
CONFIG_ADDR_HOSTS
;
continue
;
}
#endif
inet_ntop
(
prot
,
&
crec
->
addr
.
addr
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"duplicate IP address %s (%s) in dhcp-config directive"
),
daemon
->
addrbuff
,
config
->
hostname
);
}
}
#ifdef HAVE_DHCP6
if
(
prot
==
AF_INET
)
{
prot
=
AF_INET6
;
goto
again
;
}
#endif
}
#endif
src/dhcp.c
View file @
c6cc03ed
...
@@ -119,42 +119,6 @@ void dhcp_init(void)
...
@@ -119,42 +119,6 @@ void dhcp_init(void)
#endif
#endif
check_dhcp_hosts
(
1
);
check_dhcp_hosts
(
1
);
expand_buf
(
&
daemon
->
dhcp_packet
,
sizeof
(
struct
dhcp_packet
));
}
ssize_t
recv_dhcp_packet
(
int
fd
,
struct
msghdr
*
msg
)
{
ssize_t
sz
;
while
(
1
)
{
msg
->
msg_flags
=
0
;
while
((
sz
=
recvmsg
(
fd
,
msg
,
MSG_PEEK
|
MSG_TRUNC
))
==
-
1
&&
errno
==
EINTR
);
if
(
sz
==
-
1
)
return
-
1
;
if
(
!
(
msg
->
msg_flags
&
MSG_TRUNC
))
break
;
/* Very new Linux kernels return the actual size needed,
older ones always return truncated size */
if
((
size_t
)
sz
==
daemon
->
dhcp_packet
.
iov_len
)
{
if
(
!
expand_buf
(
&
daemon
->
dhcp_packet
,
sz
+
100
))
return
-
1
;
}
else
{
expand_buf
(
&
daemon
->
dhcp_packet
,
sz
);
break
;
}
}
while
((
sz
=
recvmsg
(
fd
,
msg
,
0
))
==
-
1
&&
errno
==
EINTR
);
return
(
msg
->
msg_flags
&
MSG_TRUNC
)
?
-
1
:
sz
;
}
}
void
dhcp_packet
(
time_t
now
,
int
pxe_fd
)
void
dhcp_packet
(
time_t
now
,
int
pxe_fd
)
...
@@ -610,50 +574,6 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
...
@@ -610,50 +574,6 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
return
NULL
;
return
NULL
;
}
}
/* Is every member of check matched by a member of pool?
If tagnotneeded, untagged is OK */
int
match_netid
(
struct
dhcp_netid
*
check
,
struct
dhcp_netid
*
pool
,
int
tagnotneeded
)
{
struct
dhcp_netid
*
tmp1
;
if
(
!
check
&&
!
tagnotneeded
)
return
0
;
for
(;
check
;
check
=
check
->
next
)
{
/* '#' for not is for backwards compat. */
if
(
check
->
net
[
0
]
!=
'!'
&&
check
->
net
[
0
]
!=
'#'
)
{
for
(
tmp1
=
pool
;
tmp1
;
tmp1
=
tmp1
->
next
)
if
(
strcmp
(
check
->
net
,
tmp1
->
net
)
==
0
)
break
;
if
(
!
tmp1
)
return
0
;
}
else
for
(
tmp1
=
pool
;
tmp1
;
tmp1
=
tmp1
->
next
)
if
(
strcmp
((
check
->
net
)
+
1
,
tmp1
->
net
)
==
0
)
return
0
;
}
return
1
;
}
struct
dhcp_netid
*
run_tag_if
(
struct
dhcp_netid
*
tags
)
{
struct
tag_if
*
exprs
;
struct
dhcp_netid_list
*
list
;
for
(
exprs
=
daemon
->
tag_if
;
exprs
;
exprs
=
exprs
->
next
)
if
(
match_netid
(
exprs
->
tag
,
tags
,
1
))
for
(
list
=
exprs
->
set
;
list
;
list
=
list
->
next
)
{
list
->
list
->
next
=
tags
;
tags
=
list
->
list
;
}
return
tags
;
}
int
address_allocate
(
struct
dhcp_context
*
context
,
int
address_allocate
(
struct
dhcp_context
*
context
,
struct
in_addr
*
addrp
,
unsigned
char
*
hwaddr
,
int
hw_len
,
struct
in_addr
*
addrp
,
unsigned
char
*
hwaddr
,
int
hw_len
,
struct
dhcp_netid
*
netids
,
time_t
now
)
struct
dhcp_netid
*
netids
,
time_t
now
)
...
@@ -849,7 +769,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
...
@@ -849,7 +769,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
is_addr_in_context
(
context
,
config
))
is_addr_in_context
(
context
,
config
))
return
config
;
return
config
;
/* use match with fewest wildca
st
octets */
/* use match with fewest wildca
rd
octets */
for
(
candidate
=
NULL
,
count
=
0
,
config
=
configs
;
config
;
config
=
config
->
next
)
for
(
candidate
=
NULL
,
count
=
0
,
config
=
configs
;
config
;
config
=
config
->
next
)
if
(
is_addr_in_context
(
context
,
config
))
if
(
is_addr_in_context
(
context
,
config
))
for
(
conf_addr
=
config
->
hwaddr
;
conf_addr
;
conf_addr
=
conf_addr
->
next
)
for
(
conf_addr
=
config
->
hwaddr
;
conf_addr
;
conf_addr
=
conf_addr
->
next
)
...
@@ -1026,85 +946,6 @@ void dhcp_read_ethers(void)
...
@@ -1026,85 +946,6 @@ void dhcp_read_ethers(void)
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"read %s - %d addresses"
),
ETHERSFILE
,
count
);
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"read %s - %d addresses"
),
ETHERSFILE
,
count
);
}
}
void
check_dhcp_hosts
(
int
fatal
)
{
/* If the same IP appears in more than one host config, then DISCOVER
for one of the hosts will get the address, but REQUEST will be NAKed,
since the address is reserved by the other one -> protocol loop.
Also check that FQDNs match the domain we are using. */
struct
dhcp_config
*
configs
,
*
cp
;
for
(
configs
=
daemon
->
dhcp_conf
;
configs
;
configs
=
configs
->
next
)
{
char
*
domain
;
if
((
configs
->
flags
&
DHOPT_BANK
)
||
fatal
)
{
for
(
cp
=
configs
->
next
;
cp
;
cp
=
cp
->
next
)
if
((
configs
->
flags
&
cp
->
flags
&
CONFIG_ADDR
)
&&
configs
->
addr
.
s_addr
==
cp
->
addr
.
s_addr
)
{
if
(
fatal
)
die
(
_
(
"duplicate IP address %s in dhcp-config directive."
),
inet_ntoa
(
cp
->
addr
),
EC_BADCONF
);
else
my_syslog
(
MS_DHCP
|
LOG_ERR
,
_
(
"duplicate IP address %s in %s."
),
inet_ntoa
(
cp
->
addr
),
daemon
->
dhcp_hosts_file
);
configs
->
flags
&=
~
CONFIG_ADDR
;
}
/* split off domain part */
if
((
configs
->
flags
&
CONFIG_NAME
)
&&
(
domain
=
strip_hostname
(
configs
->
hostname
)))
configs
->
domain
=
domain
;
}
}
}
void
dhcp_update_configs
(
struct
dhcp_config
*
configs
)
{
/* Some people like to keep all static IP addresses in /etc/hosts.
This goes through /etc/hosts and sets static addresses for any DHCP config
records which don't have an address and whose name matches.
We take care to maintain the invariant that any IP address can appear
in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
restore the status-quo ante first. */
struct
dhcp_config
*
config
;
struct
crec
*
crec
;
for
(
config
=
configs
;
config
;
config
=
config
->
next
)
if
(
config
->
flags
&
CONFIG_ADDR_HOSTS
)
config
->
flags
&=
~
(
CONFIG_ADDR
|
CONFIG_ADDR_HOSTS
);
if
(
daemon
->
port
!=
0
)
for
(
config
=
configs
;
config
;
config
=
config
->
next
)
if
(
!
(
config
->
flags
&
CONFIG_ADDR
)
&&
(
config
->
flags
&
CONFIG_NAME
)
&&
(
crec
=
cache_find_by_name
(
NULL
,
config
->
hostname
,
0
,
F_IPV4
))
&&
(
crec
->
flags
&
F_HOSTS
))
{
if
(
cache_find_by_name
(
crec
,
config
->
hostname
,
0
,
F_IPV4
))
{
/* use primary (first) address */
while
(
crec
&&
!
(
crec
->
flags
&
F_REVERSE
))
crec
=
cache_find_by_name
(
crec
,
config
->
hostname
,
0
,
F_IPV4
);
if
(
!
crec
)
continue
;
/* should be never */
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"%s has more than one address in hostsfile, using %s for DHCP"
),
config
->
hostname
,
inet_ntoa
(
crec
->
addr
.
addr
.
addr
.
addr4
));
}
if
(
config_find_by_address
(
configs
,
crec
->
addr
.
addr
.
addr
.
addr4
))
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"duplicate IP address %s (%s) in dhcp-config directive"
),
inet_ntoa
(
crec
->
addr
.
addr
.
addr
.
addr4
),
config
->
hostname
);
else
{
config
->
addr
=
crec
->
addr
.
addr
.
addr
.
addr4
;
config
->
flags
|=
CONFIG_ADDR
|
CONFIG_ADDR_HOSTS
;
}
}
}
/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
for this address. If it has a domain part, that must match the set domain and
for this address. If it has a domain part, that must match the set domain and
...
@@ -1145,20 +986,5 @@ char *host_from_dns(struct in_addr addr)
...
@@ -1145,20 +986,5 @@ char *host_from_dns(struct in_addr addr)
return
NULL
;
return
NULL
;
}
}
/* return domain or NULL if none. */
char
*
strip_hostname
(
char
*
hostname
)
{
char
*
dot
=
strchr
(
hostname
,
'.'
);
if
(
!
dot
)
return
NULL
;
*
dot
=
0
;
/* truncate */
if
(
strlen
(
dot
+
1
)
!=
0
)
return
dot
+
1
;
return
NULL
;
}
#endif
#endif
src/dhcp6.c
View file @
c6cc03ed
...
@@ -23,27 +23,40 @@ struct iface_param {
...
@@ -23,27 +23,40 @@ struct iface_param {
int
ind
;
int
ind
;
};
};
struct
listen_param
{
int
fd_or_iface
;
struct
listen_param
*
next
;
};
static
int
join_multicast
(
struct
in6_addr
*
local
,
int
prefix
,
static
int
join_multicast
(
struct
in6_addr
*
local
,
int
prefix
,
int
scope
,
int
if_index
,
int
dad
,
void
*
vparam
);
int
scope
,
int
if_index
,
int
dad
,
void
*
vparam
);
static
int
complete_context6
(
struct
in6_addr
*
local
,
int
prefix
,
static
int
complete_context6
(
struct
in6_addr
*
local
,
int
prefix
,
int
scope
,
int
if_index
,
int
dad
,
void
*
vparam
);
int
scope
,
int
if_index
,
int
dad
,
void
*
vparam
);
static
int
make_duid1
(
unsigned
int
type
,
unsigned
int
flags
,
char
*
mac
,
size_t
maclen
,
void
*
parm
);
void
dhcp6_init
(
void
)
void
dhcp6_init
(
void
)
{
{
int
fd
;
int
fd
;
struct
sockaddr_in6
saddr
;
struct
sockaddr_in6
saddr
;
struct
listen_param
*
listenp
,
listen
;
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
int
class
=
IPTOS_CLASS_CS6
;
int
class
=
IPTOS_CLASS_CS6
;
#endif
if
((
fd
=
socket
(
PF_INET6
,
SOCK_DGRAM
,
IPPROTO_UDP
))
==
-
1
||
if
((
fd
=
socket
(
PF_INET6
,
SOCK_DGRAM
,
IPPROTO_UDP
))
==
-
1
||
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
setsockopt
(
fd
,
IPPROTO_IPV6
,
IPV6_TCLASS
,
&
class
,
sizeof
(
class
))
==
-
1
||
setsockopt
(
fd
,
IPPROTO_IPV6
,
IPV6_TCLASS
,
&
class
,
sizeof
(
class
))
==
-
1
||
#endif
!
fix_fd
(
fd
)
||
!
fix_fd
(
fd
)
||
!
set_ipv6pktinfo
(
fd
))
!
set_ipv6pktinfo
(
fd
))
die
(
_
(
"cannot create DHCPv6 socket: %s"
),
NULL
,
EC_BADNET
);
die
(
_
(
"cannot create DHCPv6 socket: %s"
),
NULL
,
EC_BADNET
);
memset
(
&
saddr
,
0
,
sizeof
(
saddr
));
memset
(
&
saddr
,
0
,
sizeof
(
saddr
));
#ifdef HAVE_SOCKADDR_SA_LEN
#ifdef HAVE_SOCKADDR_SA_LEN
saddr
.
sin6_len
=
sizeof
(
addr
.
in6
);
saddr
.
sin6_len
=
sizeof
(
struct
sockaddr_
in6
);
#endif
#endif
saddr
.
sin6_family
=
AF_INET6
;
saddr
.
sin6_family
=
AF_INET6
;
saddr
.
sin6_addr
=
in6addr_any
;
saddr
.
sin6_addr
=
in6addr_any
;
...
@@ -53,16 +66,18 @@ void dhcp6_init(void)
...
@@ -53,16 +66,18 @@ void dhcp6_init(void)
die
(
_
(
"failed to bind DHCPv6 server socket: %s"
),
NULL
,
EC_BADNET
);
die
(
_
(
"failed to bind DHCPv6 server socket: %s"
),
NULL
,
EC_BADNET
);
/* join multicast groups on each interface we're interested in */
/* join multicast groups on each interface we're interested in */
if
(
!
iface_enumerate
(
AF_INET6
,
&
fd
,
join_multicast
))
listen
.
fd_or_iface
=
fd
;
listen
.
next
=
NULL
;
if
(
!
iface_enumerate
(
AF_INET6
,
&
listen
,
join_multicast
))
die
(
_
(
"failed to join DHCPv6 multicast group: %s"
),
NULL
,
EC_BADNET
);
die
(
_
(
"failed to join DHCPv6 multicast group: %s"
),
NULL
,
EC_BADNET
);
for
(
listenp
=
listen
.
next
;
listenp
;
)
{
struct
listen_param
*
tmp
=
listenp
->
next
;
free
(
listenp
);
listenp
=
tmp
;
}
daemon
->
dhcp6fd
=
fd
;
daemon
->
dhcp6fd
=
fd
;
/* If we've already inited DHCPv4, this becomes a no-op,
othewise sizeof(struct dhcp_packet) is as good an initial
size as any. */
expand_buf
(
&
daemon
->
dhcp_packet
,
sizeof
(
struct
dhcp_packet
));
expand_buf
(
&
daemon
->
outpacket
,
sizeof
(
struct
dhcp_packet
));
}
}
static
int
join_multicast
(
struct
in6_addr
*
local
,
int
prefix
,
static
int
join_multicast
(
struct
in6_addr
*
local
,
int
prefix
,
...
@@ -70,20 +85,25 @@ static int join_multicast(struct in6_addr *local, int prefix,
...
@@ -70,20 +85,25 @@ static int join_multicast(struct in6_addr *local, int prefix,
{
{
char
ifrn_name
[
IFNAMSIZ
];
char
ifrn_name
[
IFNAMSIZ
];
struct
ipv6_mreq
mreq
;
struct
ipv6_mreq
mreq
;
struct
in6_addr
maddr
;
struct
listen_param
*
listenp
,
*
param
=
vparam
;
int
fd
=
*
((
int
*
)
vparam
)
;
int
fd
=
param
->
fd_or_iface
;
struct
dhcp_context
*
context
;
struct
dhcp_context
*
context
;
struct
iname
*
tmp
;
struct
iname
*
tmp
;
(
void
)
prefix
;
(
void
)
prefix
;
(
void
)
scope
;
(
void
)
dad
;
/* record which interfaces we join on, so
that we do it at most one per interface, even when they
have multiple addresses */
for
(
listenp
=
param
->
next
;
listenp
;
listenp
=
listenp
->
next
)
if
(
if_index
==
listenp
->
fd_or_iface
)
return
1
;
/* scope == link */
if
(
scope
!=
253
)
return
1
;
if
(
!
indextoname
(
fd
,
if_index
,
ifrn_name
))
if
(
!
indextoname
(
fd
,
if_index
,
ifrn_name
))
return
0
;
return
0
;
/* Are we doing DHCP on this interface? */
/* Are we doing DHCP on this interface? */
if
(
!
iface_check
(
AF_INET6
,
(
struct
all_addr
*
)
local
,
ifrn_name
))
if
(
!
iface_check
(
AF_INET6
,
(
struct
all_addr
*
)
local
,
ifrn_name
))
return
1
;
return
1
;
...
@@ -111,8 +131,12 @@ static int join_multicast(struct in6_addr *local, int prefix,
...
@@ -111,8 +131,12 @@ static int join_multicast(struct in6_addr *local, int prefix,
if
(
setsockopt
(
fd
,
IPPROTO_IPV6
,
IPV6_JOIN_GROUP
,
&
mreq
,
sizeof
(
mreq
))
==
-
1
)
if
(
setsockopt
(
fd
,
IPPROTO_IPV6
,
IPV6_JOIN_GROUP
,
&
mreq
,
sizeof
(
mreq
))
==
-
1
)
return
0
;
return
0
;
listenp
=
whine_malloc
(
sizeof
(
struct
listen_param
));
listenp
->
fd_or_iface
=
if_index
;
listenp
->
next
=
param
->
next
;
param
->
next
=
listenp
;
return
1
;
return
1
;
}
}
...
@@ -176,7 +200,7 @@ void dhcp6_packet(time_t now)
...
@@ -176,7 +200,7 @@ void dhcp6_packet(time_t now)
if
(
!
context
)
if
(
!
context
)
return
;
return
;
/* unlinked contexts are marked by context->current == context */
/* unlinked contexts are marked by context->current == context */
for
(
context
=
daemon
->
dhcp6
;
context
;
context
=
context
->
next
)
for
(
context
=
daemon
->
dhcp6
;
context
;
context
=
context
->
next
)
context
->
current
=
context
;
context
->
current
=
context
;
...
@@ -190,14 +214,15 @@ void dhcp6_packet(time_t now)
...
@@ -190,14 +214,15 @@ void dhcp6_packet(time_t now)
lease_prune
(
NULL
,
now
);
/* lose any expired leases */
lease_prune
(
NULL
,
now
);
/* lose any expired leases */
msg
.
msg_iov
=
&
daemon
->
dhcp_packet
;
msg
.
msg_iov
=
&
daemon
->
dhcp_packet
;
sz
=
dhcp6_reply
(
parm
.
current
,
sz
,
now
);
sz
=
dhcp6_reply
(
parm
.
current
,
if_index
,
ifr
.
ifr_name
,
sz
,
IN6_IS_ADDR_MULTICAST
(
&
from
)
,
now
);
/* ifr.ifr_name, if_index, (size_t)sz,
/* ifr.ifr_name, if_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd, iface_addr); */
now, unicast_dest, &is_inform, pxe_fd, iface_addr); */
lease_update_file
(
now
);
lease_update_file
(
now
);
lease_update_dns
();
lease_update_dns
();
if
(
sz
!=
0
)
if
(
sz
!=
0
)
send_from
(
daemon
->
dhcp6fd
,
0
,
daemon
->
outpacket
.
iov_base
,
sz
,
&
from
,
&
dest
,
if_index
);
while
(
sendto
(
daemon
->
dhcp6fd
,
daemon
->
outpacket
.
iov_base
,
sz
,
0
,
(
struct
sockaddr
*
)
&
from
,
sizeof
(
from
))
&&
retry_send
());
}
}
static
int
complete_context6
(
struct
in6_addr
*
local
,
int
prefix
,
static
int
complete_context6
(
struct
in6_addr
*
local
,
int
prefix
,
...
@@ -205,11 +230,16 @@ static int complete_context6(struct in6_addr *local, int prefix,
...
@@ -205,11 +230,16 @@ static int complete_context6(struct in6_addr *local, int prefix,
{
{
struct
dhcp_context
*
context
;
struct
dhcp_context
*
context
;
struct
iface_param
*
param
=
vparam
;
struct
iface_param
*
param
=
vparam
;
(
void
)
scope
;
/* warning */
(
void
)
scope
;
/* warning */
(
void
)
dad
;
for
(
context
=
daemon
->
dhcp6
;
context
;
context
=
context
->
next
)
for
(
context
=
daemon
->
dhcp6
;
context
;
context
=
context
->
next
)
{
{
if
(
prefix
==
context
->
prefix
&&
if
(
prefix
==
context
->
prefix
&&
!
IN6_IS_ADDR_LOOPBACK
(
local
)
&&
!
IN6_IS_ADDR_LINKLOCAL
(
local
)
&&
!
IN6_IS_ADDR_MULTICAST
(
local
)
&&
is_same_net6
(
local
,
&
context
->
start6
,
prefix
)
&&
is_same_net6
(
local
,
&
context
->
start6
,
prefix
)
&&
is_same_net6
(
local
,
&
context
->
end6
,
prefix
))
is_same_net6
(
local
,
&
context
->
end6
,
prefix
))
{
{
...
@@ -218,6 +248,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
...
@@ -218,6 +248,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
{
{
context
->
current
=
param
->
current
;
context
->
current
=
param
->
current
;
param
->
current
=
context
;
param
->
current
=
context
;
context
->
local6
=
*
local
;
}
}
}
}
}
}
...
@@ -238,7 +269,7 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
...
@@ -238,7 +269,7 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
}
}
int
address6_allocate
(
struct
dhcp_context
*
context
,
unsigned
char
*
clid
,
int
clid_len
,
int
address6_allocate
(
struct
dhcp_context
*
context
,
unsigned
char
*
clid
,
int
clid_len
,
struct
dhcp_netid
*
netids
,
struct
in6_addr
*
ans
)
int
serial
,
struct
dhcp_netid
*
netids
,
struct
in6_addr
*
ans
)
{
{
/* Find a free address: exclude anything in use and anything allocated to
/* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration.
a particular hwaddr/clientid/hostname in our configuration.
...
@@ -266,7 +297,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
...
@@ -266,7 +297,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
continue
;
continue
;
else
else
{
{
start
=
addr6part
(
&
c
->
start6
)
+
((
j
+
c
->
addr_epoch
)
%
(
1
+
addr6part
(
&
c
->
end6
)
-
addr6part
(
&
c
->
start6
)));
start
=
addr6part
(
&
c
->
start6
)
+
((
j
+
c
->
addr_epoch
+
serial
)
%
(
1
+
addr6part
(
&
c
->
end6
)
-
addr6part
(
&
c
->
start6
)));
/* iterate until we find a free address. */
/* iterate until we find a free address. */
addr
=
start
;
addr
=
start
;
...
@@ -358,6 +389,133 @@ struct dhcp_context *narrow_context6(struct dhcp_context *context,
...
@@ -358,6 +389,133 @@ struct dhcp_context *narrow_context6(struct dhcp_context *context,
return
tmp
;
return
tmp
;
}
}
static
int
is_addr_in_context6
(
struct
dhcp_context
*
context
,
struct
dhcp_config
*
config
)
{
if
(
!
context
)
/* called via find_config() from lease_update_from_configs() */
return
1
;
if
(
!
(
config
->
flags
&
CONFIG_ADDR6
))
return
1
;
for
(;
context
;
context
=
context
->
current
)
if
(
is_same_net6
(
&
config
->
addr6
,
&
context
->
start6
,
context
->
prefix
))
return
1
;
return
0
;
}
struct
dhcp_config
*
find_config6
(
struct
dhcp_config
*
configs
,
struct
dhcp_context
*
context
,
unsigned
char
*
duid
,
int
duid_len
,
char
*
hostname
)
{
int
count
,
new
;
struct
dhcp_config
*
config
;
struct
hwaddr_config
*
conf_addr
;
unsigned
char
*
hwaddr
=
NULL
;
int
duid_type
,
hw_len
=
0
,
hw_type
=
0
;
if
(
duid
)
{
for
(
config
=
configs
;
config
;
config
=
config
->
next
)
if
(
config
->
flags
&
CONFIG_CLID
)
{
if
(
config
->
clid_len
==
duid_len
&&
memcmp
(
config
->
clid
,
duid
,
duid_len
)
==
0
&&
is_addr_in_context6
(
context
,
config
))
return
config
;
}
/* DHCPv6 doesn't deal in MAC addresses per-se, but some DUIDs do include
MAC addresses, so we try and parse them out here. Not that there is only one
DUID per host and it's created using any one of the MACs, so this is no
good no good for multihomed hosts. */
hwaddr
=
duid
;
GETSHORT
(
duid_type
,
hwaddr
);
if
(
duid_type
==
1
||
duid_type
==
3
)
{
GETSHORT
(
hw_type
,
hwaddr
);
if
(
duid_type
==
1
)
hwaddr
+=
4
;
/* skip time */
hw_len
=
duid_len
-
8
;
}
if
(
hwaddr
)
for
(
config
=
configs
;
config
;
config
=
config
->
next
)
if
(
config_has_mac
(
config
,
hwaddr
,
hw_len
,
hw_type
)
&&
is_addr_in_context6
(
context
,
config
))
return
config
;
}
if
(
hostname
&&
context
)
for
(
config
=
configs
;
config
;
config
=
config
->
next
)
if
((
config
->
flags
&
CONFIG_NAME
)
&&
hostname_isequal
(
config
->
hostname
,
hostname
)
&&
is_addr_in_context6
(
context
,
config
))
return
config
;
/* use match with fewest wildcard octets */
if
(
hwaddr
)
{
struct
dhcp_config
*
candidate
;
for
(
candidate
=
NULL
,
count
=
0
,
config
=
configs
;
config
;
config
=
config
->
next
)
if
(
is_addr_in_context6
(
context
,
config
))
for
(
conf_addr
=
config
->
hwaddr
;
conf_addr
;
conf_addr
=
conf_addr
->
next
)
if
(
conf_addr
->
wildcard_mask
!=
0
&&
conf_addr
->
hwaddr_len
==
hw_len
&&
(
conf_addr
->
hwaddr_type
==
hw_type
||
conf_addr
->
hwaddr_type
==
0
)
&&
(
new
=
memcmp_masked
(
conf_addr
->
hwaddr
,
hwaddr
,
hw_len
,
conf_addr
->
wildcard_mask
))
>
count
)
{
count
=
new
;
candidate
=
config
;
}
return
candidate
;
}
return
NULL
;
}
void
make_duid
(
time_t
now
)
{
/* rebase epoch to 1/1/2000 */
time_t
newnow
=
now
-
946684800
;
iface_enumerate
(
AF_LOCAL
,
&
newnow
,
make_duid1
);
if
(
!
daemon
->
duid
)
die
(
"Cannot create DHCPv6 server DUID"
,
NULL
,
EC_MISC
);
}
static
int
make_duid1
(
unsigned
int
type
,
unsigned
int
flags
,
char
*
mac
,
size_t
maclen
,
void
*
parm
)
{
/* create DUID as specified in RFC3315. We use the MAC of the
first interface we find that isn't loopback or P-to-P */
unsigned
char
*
p
;
if
(
flags
&
(
IFF_LOOPBACK
|
IFF_POINTOPOINT
))
return
1
;
daemon
->
duid
=
p
=
safe_malloc
(
maclen
+
8
);
daemon
->
duid_len
=
maclen
+
8
;
#ifdef HAVE_BROKEN_RTC
PUTSHORT
(
3
,
p
);
/* DUID_LL */
#else
PUTSHORT
(
1
,
p
);
/* DUID_LLT */
#endif
PUTSHORT
(
type
,
p
);
/* address type */
#ifndef HAVE_BROKEN_RTC
PUTLONG
(
*
((
time_t
*
)
parm
),
p
);
/* time */
#endif
memcpy
(
p
,
mac
,
maclen
);
return
0
;
}
#endif
#endif
src/dhcp6_protocol.h
View file @
c6cc03ed
...
@@ -53,7 +53,10 @@
...
@@ -53,7 +53,10 @@
#define OPTION6_INTERFACE_ID 18
#define OPTION6_INTERFACE_ID 18
#define OPTION6_RECONFIGURE_MSG 19
#define OPTION6_RECONFIGURE_MSG 19
#define OPTION6_RECONF_ACCEPT 20
#define OPTION6_RECONF_ACCEPT 20
#define OPTION6_DNS_SERVER 23
#define OPTION6_REMOTE_ID 37
#define OPTION6_SUBSCRIBER_ID 38
#define OPTION6_FQDN 39
#define DHCP6SUCCESS 0
#define DHCP6SUCCESS 0
#define DHCP6UNSPEC 1
#define DHCP6UNSPEC 1
...
...
src/dnsmasq.c
View file @
c6cc03ed
...
@@ -150,7 +150,9 @@ int main (int argc, char **argv)
...
@@ -150,7 +150,9 @@ int main (int argc, char **argv)
{
{
/* Note that order matters here, we must call lease_init before
/* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked
creating any file descriptors which shouldn't be leaked
to the lease-script init process. */
to the lease-script init process. We need to call common_init
before lease_init to allocate buffers it uses.*/
dhcp_common_init
();
lease_init
(
now
);
lease_init
(
now
);
if
(
daemon
->
dhcp
)
if
(
daemon
->
dhcp
)
dhcp_init
();
dhcp_init
();
...
...
src/dnsmasq.h
View file @
c6cc03ed
...
@@ -436,15 +436,20 @@ struct frec {
...
@@ -436,15 +436,20 @@ struct frec {
#define ACTION_OLD 3
#define ACTION_OLD 3
#define ACTION_ADD 4
#define ACTION_ADD 4
#define LEASE_NEW 1
/* newly created */
#define LEASE_CHANGED 2
/* modified */
#define LEASE_AUX_CHANGED 4
/* CLID or expiry changed */
#define LEASE_AUTH_NAME 8
/* hostname came from config, not from client */
#define LEASE_USED 16
/* used this DHCPv6 transaction */
#define LEASE_NA 32
/* IPv6 no-temporary lease */
#define LEASE_TA 64
/* IPv6 temporary lease */
struct
dhcp_lease
{
struct
dhcp_lease
{
int
clid_len
;
/* length of client identifier */
int
clid_len
;
/* length of client identifier */
unsigned
char
*
clid
;
/* clientid */
unsigned
char
*
clid
;
/* clientid */
char
*
hostname
,
*
fqdn
;
/* name from client-hostname option or config */
char
*
hostname
,
*
fqdn
;
/* name from client-hostname option or config */
char
*
old_hostname
;
/* hostname before it moved to another lease */
char
*
old_hostname
;
/* hostname before it moved to another lease */
char
auth_name
;
/* hostname came from config, not from client */
int
flags
;
char
new
;
/* newly created */
char
changed
;
/* modified */
char
aux_changed
;
/* CLID or expiry changed */
time_t
expires
;
/* lease expiry */
time_t
expires
;
/* lease expiry */
#ifdef HAVE_BROKEN_RTC
#ifdef HAVE_BROKEN_RTC
unsigned
int
length
;
unsigned
int
length
;
...
@@ -455,9 +460,6 @@ struct dhcp_lease {
...
@@ -455,9 +460,6 @@ struct dhcp_lease {
unsigned
char
*
extradata
;
unsigned
char
*
extradata
;
unsigned
int
extradata_len
,
extradata_size
;
unsigned
int
extradata_len
,
extradata_size
;
int
last_interface
;
int
last_interface
;
#ifdef HAVE_DHCP6
char
is_ipv6
;
#endif
struct
dhcp_lease
*
next
;
struct
dhcp_lease
*
next
;
};
};
...
@@ -500,6 +502,8 @@ struct dhcp_config {
...
@@ -500,6 +502,8 @@ struct dhcp_config {
struct
dhcp_config
*
next
;
struct
dhcp_config
*
next
;
};
};
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
#define CONFIG_DISABLE 1
#define CONFIG_DISABLE 1
#define CONFIG_CLID 2
#define CONFIG_CLID 2
#define CONFIG_TIME 8
#define CONFIG_TIME 8
...
@@ -537,6 +541,7 @@ struct dhcp_opt {
...
@@ -537,6 +541,7 @@ struct dhcp_opt {
#define DHOPT_VENDOR_MATCH 1024
#define DHOPT_VENDOR_MATCH 1024
#define DHOPT_RFC3925 2048
#define DHOPT_RFC3925 2048
#define DHOPT_TAGOK 4096
#define DHOPT_TAGOK 4096
#define DHOPT_ADDR6 8192
struct
dhcp_boot
{
struct
dhcp_boot
{
char
*
file
,
*
sname
,
*
tftp_sname
;
char
*
file
,
*
sname
,
*
tftp_sname
;
...
@@ -561,7 +566,8 @@ struct pxe_service {
...
@@ -561,7 +566,8 @@ struct pxe_service {
/* vendorclass, userclass, remote-id or cicuit-id */
/* vendorclass, userclass, remote-id or cicuit-id */
struct
dhcp_vendor
{
struct
dhcp_vendor
{
int
len
,
match_type
,
option
;
int
len
,
match_type
;
unsigned
int
enterprise
;
char
*
data
;
char
*
data
;
struct
dhcp_netid
netid
;
struct
dhcp_netid
netid
;
struct
dhcp_vendor
*
next
;
struct
dhcp_vendor
*
next
;
...
@@ -583,6 +589,10 @@ struct dhcp_bridge {
...
@@ -583,6 +589,10 @@ struct dhcp_bridge {
struct
cond_domain
{
struct
cond_domain
{
char
*
domain
;
char
*
domain
;
struct
in_addr
start
,
end
;
struct
in_addr
start
,
end
;
#ifdef HAVE_IPV6
struct
in6_addr
start6
,
end6
;
#endif
int
is6
;
struct
cond_domain
*
next
;
struct
cond_domain
*
next
;
};
};
...
@@ -686,7 +696,7 @@ extern struct daemon {
...
@@ -686,7 +696,7 @@ extern struct daemon {
struct
hostsfile
*
addn_hosts
;
struct
hostsfile
*
addn_hosts
;
struct
dhcp_context
*
dhcp
,
*
dhcp6
;
struct
dhcp_context
*
dhcp
,
*
dhcp6
;
struct
dhcp_config
*
dhcp_conf
;
struct
dhcp_config
*
dhcp_conf
;
struct
dhcp_opt
*
dhcp_opts
,
*
dhcp_match
,
*
dhcp_opts6
;
struct
dhcp_opt
*
dhcp_opts
,
*
dhcp_match
,
*
dhcp_opts6
,
*
dhcp_match6
;
struct
dhcp_vendor
*
dhcp_vendors
;
struct
dhcp_vendor
*
dhcp_vendors
;
struct
dhcp_mac
*
dhcp_macs
;
struct
dhcp_mac
*
dhcp_macs
;
struct
dhcp_boot
*
boot_config
;
struct
dhcp_boot
*
boot_config
;
...
@@ -776,12 +786,15 @@ void cache_start_insert(void);
...
@@ -776,12 +786,15 @@ void cache_start_insert(void);
struct
crec
*
cache_insert
(
char
*
name
,
struct
all_addr
*
addr
,
struct
crec
*
cache_insert
(
char
*
name
,
struct
all_addr
*
addr
,
time_t
now
,
unsigned
long
ttl
,
unsigned
short
flags
);
time_t
now
,
unsigned
long
ttl
,
unsigned
short
flags
);
void
cache_reload
(
void
);
void
cache_reload
(
void
);
void
cache_add_dhcp_entry
(
char
*
host_name
,
struct
in
_addr
*
host_address
,
time_t
ttd
);
void
cache_add_dhcp_entry
(
char
*
host_name
,
int
prot
,
struct
all
_addr
*
host_address
,
time_t
ttd
);
struct
in_addr
a_record_from_hosts
(
char
*
name
,
time_t
now
);
struct
in_addr
a_record_from_hosts
(
char
*
name
,
time_t
now
);
void
cache_unhash_dhcp
(
void
);
void
cache_unhash_dhcp
(
void
);
void
dump_cache
(
time_t
now
);
void
dump_cache
(
time_t
now
);
char
*
cache_get_name
(
struct
crec
*
crecp
);
char
*
cache_get_name
(
struct
crec
*
crecp
);
char
*
get_domain
(
struct
in_addr
addr
);
char
*
get_domain
(
struct
in_addr
addr
);
#ifdef HAVE_IPV6
char
*
get_domain6
(
struct
in6_addr
*
addr
);
#endif
/* rfc1035.c */
/* rfc1035.c */
unsigned
int
extract_request
(
struct
dns_header
*
header
,
size_t
qlen
,
unsigned
int
extract_request
(
struct
dns_header
*
header
,
size_t
qlen
,
...
@@ -845,7 +858,8 @@ void flush_log(void);
...
@@ -845,7 +858,8 @@ void flush_log(void);
/* option.c */
/* option.c */
void
read_opts
(
int
argc
,
char
**
argv
,
char
*
compile_opts
);
void
read_opts
(
int
argc
,
char
**
argv
,
char
*
compile_opts
);
char
*
option_string
(
unsigned
char
opt
,
int
*
is_ip
,
int
*
is_name
);
char
*
option_string
(
int
prot
,
unsigned
int
opt
,
unsigned
char
*
val
,
int
opt_len
,
char
*
buf
,
int
buf_len
);
void
reread_dhcp
(
void
);
void
reread_dhcp
(
void
);
void
set_option_bool
(
unsigned
int
opt
);
void
set_option_bool
(
unsigned
int
opt
);
struct
hostsfile
*
expand_filelist
(
struct
hostsfile
*
list
);
struct
hostsfile
*
expand_filelist
(
struct
hostsfile
*
list
);
...
@@ -883,31 +897,24 @@ int set_ipv6pktinfo(int fd);
...
@@ -883,31 +897,24 @@ int set_ipv6pktinfo(int fd);
#ifdef HAVE_DHCP
#ifdef HAVE_DHCP
void
dhcp_init
(
void
);
void
dhcp_init
(
void
);
void
dhcp_packet
(
time_t
now
,
int
pxe_fd
);
void
dhcp_packet
(
time_t
now
,
int
pxe_fd
);
ssize_t
recv_dhcp_packet
(
int
fd
,
struct
msghdr
*
msg
);
struct
dhcp_context
*
address_available
(
struct
dhcp_context
*
context
,
struct
dhcp_context
*
address_available
(
struct
dhcp_context
*
context
,
struct
in_addr
addr
,
struct
in_addr
addr
,
struct
dhcp_netid
*
netids
);
struct
dhcp_netid
*
netids
);
struct
dhcp_context
*
narrow_context
(
struct
dhcp_context
*
context
,
struct
dhcp_context
*
narrow_context
(
struct
dhcp_context
*
context
,
struct
in_addr
taddr
,
struct
in_addr
taddr
,
struct
dhcp_netid
*
netids
);
struct
dhcp_netid
*
netids
);
int
match_netid
(
struct
dhcp_netid
*
check
,
struct
dhcp_netid
*
pool
,
int
negonly
);
int
address_allocate
(
struct
dhcp_context
*
context
,
int
address_allocate
(
struct
dhcp_context
*
context
,
struct
in_addr
*
addrp
,
unsigned
char
*
hwaddr
,
int
hw_len
,
struct
in_addr
*
addrp
,
unsigned
char
*
hwaddr
,
int
hw_len
,
struct
dhcp_netid
*
netids
,
time_t
now
);
struct
dhcp_netid
*
netids
,
time_t
now
);
struct
dhcp_netid
*
run_tag_if
(
struct
dhcp_netid
*
input
);
int
config_has_mac
(
struct
dhcp_config
*
config
,
unsigned
char
*
hwaddr
,
int
len
,
int
type
);
int
config_has_mac
(
struct
dhcp_config
*
config
,
unsigned
char
*
hwaddr
,
int
len
,
int
type
);
struct
dhcp_config
*
find_config
(
struct
dhcp_config
*
configs
,
struct
dhcp_config
*
find_config
(
struct
dhcp_config
*
configs
,
struct
dhcp_context
*
context
,
struct
dhcp_context
*
context
,
unsigned
char
*
clid
,
int
clid_len
,
unsigned
char
*
clid
,
int
clid_len
,
unsigned
char
*
hwaddr
,
int
hw_len
,
unsigned
char
*
hwaddr
,
int
hw_len
,
int
hw_type
,
char
*
hostname
);
int
hw_type
,
char
*
hostname
);
void
dhcp_update_configs
(
struct
dhcp_config
*
configs
);
void
dhcp_read_ethers
(
void
);
void
dhcp_read_ethers
(
void
);
void
check_dhcp_hosts
(
int
fatal
);
struct
dhcp_config
*
config_find_by_address
(
struct
dhcp_config
*
configs
,
struct
in_addr
addr
);
struct
dhcp_config
*
config_find_by_address
(
struct
dhcp_config
*
configs
,
struct
in_addr
addr
);
char
*
strip_hostname
(
char
*
hostname
);
char
*
host_from_dns
(
struct
in_addr
addr
);
char
*
host_from_dns
(
struct
in_addr
addr
);
char
*
get_domain
(
struct
in_addr
addr
);
#endif
#endif
/* lease.c */
/* lease.c */
...
@@ -917,13 +924,14 @@ void lease_update_dns();
...
@@ -917,13 +924,14 @@ void lease_update_dns();
void
lease_init
(
time_t
now
);
void
lease_init
(
time_t
now
);
struct
dhcp_lease
*
lease4_allocate
(
struct
in_addr
addr
);
struct
dhcp_lease
*
lease4_allocate
(
struct
in_addr
addr
);
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
struct
dhcp_lease
*
lease6_allocate
(
struct
in6_addr
*
addrp
);
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
);
struct
dhcp_lease
*
lease6_find_by_addr
(
struct
in6_addr
*
net
,
int
prefix
,
u64
addr
);
struct
dhcp_lease
*
lease6_find_by_addr
(
struct
in6_addr
*
net
,
int
prefix
,
u64
addr
);
struct
dhcp_lease
*
lease6_find_by_client
(
unsigned
char
*
clid
,
int
clid_len
,
int
iaid
);
#endif
#endif
void
lease_set_hwaddr
(
struct
dhcp_lease
*
lease
,
unsigned
char
*
hwaddr
,
void
lease_set_hwaddr
(
struct
dhcp_lease
*
lease
,
unsigned
char
*
hwaddr
,
unsigned
char
*
clid
,
int
hw_len
,
int
hw_type
,
int
clid_len
);
unsigned
char
*
clid
,
int
hw_len
,
int
hw_type
,
int
clid_len
);
void
lease_set_hostname
(
struct
dhcp_lease
*
lease
,
char
*
name
,
int
auth
);
void
lease_set_hostname
(
struct
dhcp_lease
*
lease
,
char
*
name
,
int
auth
,
char
*
domain
,
char
*
config_domain
);
void
lease_set_expires
(
struct
dhcp_lease
*
lease
,
unsigned
int
len
,
time_t
now
);
void
lease_set_expires
(
struct
dhcp_lease
*
lease
,
unsigned
int
len
,
time_t
now
);
void
lease_set_interface
(
struct
dhcp_lease
*
lease
,
int
interface
);
void
lease_set_interface
(
struct
dhcp_lease
*
lease
,
int
interface
);
struct
dhcp_lease
*
lease_find_by_client
(
unsigned
char
*
hwaddr
,
int
hw_len
,
int
hw_type
,
struct
dhcp_lease
*
lease_find_by_client
(
unsigned
char
*
hwaddr
,
int
hw_len
,
int
hw_type
,
...
@@ -934,6 +942,10 @@ void lease_prune(struct dhcp_lease *target, time_t now);
...
@@ -934,6 +942,10 @@ void lease_prune(struct dhcp_lease *target, time_t now);
void
lease_update_from_configs
(
void
);
void
lease_update_from_configs
(
void
);
int
do_script_run
(
time_t
now
);
int
do_script_run
(
time_t
now
);
void
rerun_scripts
(
void
);
void
rerun_scripts
(
void
);
#ifdef HAVE_SCRIPT
void
lease_add_extradata
(
struct
dhcp_lease
*
lease
,
unsigned
char
*
data
,
unsigned
int
len
,
int
delim
);
#endif
#endif
#endif
/* rfc2131.c */
/* rfc2131.c */
...
@@ -1005,17 +1017,38 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
...
@@ -1005,17 +1017,38 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
void
dhcp6_init
(
void
);
void
dhcp6_init
(
void
);
void
dhcp6_packet
(
time_t
now
);
void
dhcp6_packet
(
time_t
now
);
int
address6_allocate
(
struct
dhcp_context
*
context
,
unsigned
char
*
clid
,
int
clid_len
,
int
address6_allocate
(
struct
dhcp_context
*
context
,
unsigned
char
*
clid
,
int
clid_len
,
struct
dhcp_netid
*
netids
,
struct
in6_addr
*
ans
);
int
serial
,
struct
dhcp_netid
*
netids
,
struct
in6_addr
*
ans
);
struct
dhcp_context
*
address6_available
(
struct
dhcp_context
*
context
,
struct
dhcp_context
*
address6_available
(
struct
dhcp_context
*
context
,
struct
in6_addr
*
taddr
,
struct
in6_addr
*
taddr
,
struct
dhcp_netid
*
netids
);
struct
dhcp_netid
*
netids
);
struct
dhcp_context
*
narrow_context6
(
struct
dhcp_context
*
context
,
struct
dhcp_context
*
narrow_context6
(
struct
dhcp_context
*
context
,
struct
in6_addr
*
taddr
,
struct
in6_addr
*
taddr
,
struct
dhcp_netid
*
netids
);
struct
dhcp_netid
*
netids
);
struct
dhcp_config
*
find_config6
(
struct
dhcp_config
*
configs
,
struct
dhcp_context
*
context
,
unsigned
char
*
duid
,
int
duid_len
,
char
*
hostname
);
struct
dhcp_config
*
config_find_by_address6
(
struct
dhcp_config
*
configs
,
struct
in6_addr
*
net
,
int
prefix
,
u64
addr
);
void
make_duid
(
time_t
now
);
#endif
#endif
/* rfc3315.c */
/* rfc3315.c */
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
void
make_duid
(
time_t
now
);
size_t
dhcp6_reply
(
struct
dhcp_context
*
context
,
int
interface
,
char
*
iface_name
,
size_t
sz
,
int
is_multicast
,
time_t
now
);
size_t
dhcp6_reply
(
struct
dhcp_context
*
context
,
size_t
sz
,
time_t
now
);
#endif
/* dhcp-common.c */
#ifdef HAVE_DHCP
void
dhcp_common_init
(
void
);
ssize_t
recv_dhcp_packet
(
int
fd
,
struct
msghdr
*
msg
);
struct
dhcp_netid
*
run_tag_if
(
struct
dhcp_netid
*
input
);
struct
dhcp_netid
*
option_filter
(
struct
dhcp_netid
*
tags
,
struct
dhcp_netid
*
context_tags
,
struct
dhcp_opt
*
opts
);
int
match_netid
(
struct
dhcp_netid
*
check
,
struct
dhcp_netid
*
pool
,
int
negonly
);
char
*
strip_hostname
(
char
*
hostname
);
void
log_tags
(
struct
dhcp_netid
*
netid
,
u32
xid
);
int
match_bytes
(
struct
dhcp_opt
*
o
,
unsigned
char
*
p
,
int
len
);
void
dhcp_update_configs
(
struct
dhcp_config
*
configs
);
void
check_dhcp_hosts
(
int
fatal
);
#endif
#endif
src/helper.c
View file @
c6cc03ed
...
@@ -46,8 +46,9 @@ static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end,
...
@@ -46,8 +46,9 @@ static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end,
struct
script_data
struct
script_data
{
{
unsigned
char
action
,
hwaddr_len
,
hwaddr_type
;
int
flags
;
unsigned
char
clid_len
,
hostname_len
,
ed_len
;
int
action
,
hwaddr_len
,
hwaddr_type
;
int
clid_len
,
hostname_len
,
ed_len
;
struct
in_addr
addr
,
giaddr
;
struct
in_addr
addr
,
giaddr
;
unsigned
int
remaining_time
;
unsigned
int
remaining_time
;
#ifdef HAVE_BROKEN_RTC
#ifdef HAVE_BROKEN_RTC
...
@@ -57,6 +58,7 @@ struct script_data
...
@@ -57,6 +58,7 @@ struct script_data
#endif
#endif
unsigned
char
hwaddr
[
DHCP_CHADDR_MAX
];
unsigned
char
hwaddr
[
DHCP_CHADDR_MAX
];
char
interface
[
IF_NAMESIZE
];
char
interface
[
IF_NAMESIZE
];
};
};
static
struct
script_data
*
buf
=
NULL
;
static
struct
script_data
*
buf
=
NULL
;
...
@@ -173,7 +175,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
...
@@ -173,7 +175,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
char
*
p
,
*
action_str
,
*
hostname
=
NULL
,
*
domain
=
NULL
;
char
*
p
,
*
action_str
,
*
hostname
=
NULL
,
*
domain
=
NULL
;
unsigned
char
*
buf
=
(
unsigned
char
*
)
daemon
->
namebuff
;
unsigned
char
*
buf
=
(
unsigned
char
*
)
daemon
->
namebuff
;
unsigned
char
*
end
,
*
extradata
,
*
alloc_buff
=
NULL
;
unsigned
char
*
end
,
*
extradata
,
*
alloc_buff
=
NULL
;
int
err
=
0
;
int
is6
,
err
=
0
;
free
(
alloc_buff
);
free
(
alloc_buff
);
...
@@ -199,17 +201,34 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
...
@@ -199,17 +201,34 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
action_str
=
"old"
;
action_str
=
"old"
;
else
else
continue
;
continue
;
is6
=
!!
(
data
.
flags
&
(
LEASE_TA
|
LEASE_NA
));
/* stringify MAC into dhcp_buff */
if
(
!
is6
)
p
=
daemon
->
dhcp_buff
;
{
if
(
data
.
hwaddr_type
!=
ARPHRD_ETHER
||
data
.
hwaddr_len
==
0
)
/* stringify MAC into dhcp_buff */
p
+=
sprintf
(
p
,
"%.2x-"
,
data
.
hwaddr_type
);
p
=
daemon
->
dhcp_buff
;
for
(
i
=
0
;
(
i
<
data
.
hwaddr_len
)
&&
(
i
<
DHCP_CHADDR_MAX
);
i
++
)
if
(
data
.
hwaddr_type
!=
ARPHRD_ETHER
||
data
.
hwaddr_len
==
0
)
{
p
+=
sprintf
(
p
,
"%.2x-"
,
data
.
hwaddr_type
);
p
+=
sprintf
(
p
,
"%.2x"
,
data
.
hwaddr
[
i
]);
for
(
i
=
0
;
(
i
<
data
.
hwaddr_len
)
&&
(
i
<
DHCP_CHADDR_MAX
);
i
++
)
if
(
i
!=
data
.
hwaddr_len
-
1
)
{
p
+=
sprintf
(
p
,
":"
);
p
+=
sprintf
(
p
,
"%.2x"
,
data
.
hwaddr
[
i
]);
}
if
(
i
!=
data
.
hwaddr_len
-
1
)
p
+=
sprintf
(
p
,
":"
);
}
}
#ifdef HAVE_DHCP6
else
{
/* duid not MAC for IPv6 */
for
(
p
=
daemon
->
dhcp_buff
,
i
=
0
;
i
<
data
.
clid_len
;
i
++
)
{
p
+=
sprintf
(
p
,
"%.2x"
,
buf
[
i
]);
if
(
i
!=
data
.
clid_len
-
1
)
p
+=
sprintf
(
p
,
":"
);
}
}
#endif
/* expiry or length into dhcp_buff2 */
/* expiry or length into dhcp_buff2 */
#ifdef HAVE_BROKEN_RTC
#ifdef HAVE_BROKEN_RTC
...
@@ -228,12 +247,26 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
...
@@ -228,12 +247,26 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue
;
continue
;
/* CLID into packet */
/* CLID into packet */
for
(
p
=
daemon
->
packet
,
i
=
0
;
i
<
data
.
clid_len
;
i
++
)
if
(
!
is6
)
for
(
p
=
daemon
->
packet
,
i
=
0
;
i
<
data
.
clid_len
;
i
++
)
{
p
+=
sprintf
(
p
,
"%.2x"
,
buf
[
i
]);
if
(
i
!=
data
.
clid_len
-
1
)
p
+=
sprintf
(
p
,
":"
);
}
#ifdef HAVE_DHCP6
else
{
{
p
+=
sprintf
(
p
,
"%.2x"
,
buf
[
i
]);
/* or IAID and server DUID for IPv6 */
if
(
i
!=
data
.
clid_len
-
1
)
sprintf
(
daemon
->
dhcp_buff3
,
"%s%u"
,
data
.
flags
&
LEASE_TA
?
"T"
:
""
,
data
.
hwaddr_type
);
p
+=
sprintf
(
p
,
":"
);
for
(
p
=
daemon
->
packet
,
i
=
0
;
i
<
daemon
->
duid_len
;
i
++
)
{
p
+=
sprintf
(
p
,
"%.2x"
,
daemon
->
duid
[
i
]);
if
(
i
!=
daemon
->
duid_len
-
1
)
p
+=
sprintf
(
p
,
":"
);
}
}
}
#endif
buf
+=
data
.
clid_len
;
buf
+=
data
.
clid_len
;
...
@@ -253,14 +286,29 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
...
@@ -253,14 +286,29 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
extradata
=
buf
+
data
.
hostname_len
;
extradata
=
buf
+
data
.
hostname_len
;
if
(
!
is6
)
inet_ntop
(
AF_INET
,
&
data
.
addr
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
#ifdef HAVE_DHCP6
else
inet_ntop
(
AF_INET6
,
&
data
.
hwaddr
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
#endif
#ifdef HAVE_LUASCRIPT
#ifdef HAVE_LUASCRIPT
if
(
daemon
->
luascript
)
if
(
daemon
->
luascript
)
{
{
lua_getglobal
(
lua
,
"lease"
);
/* function to call */
lua_getglobal
(
lua
,
"lease"
);
/* function to call */
lua_pushstring
(
lua
,
action_str
);
/* arg1 - action */
lua_pushstring
(
lua
,
action_str
);
/* arg1 - action */
lua_newtable
(
lua
);
/* arg2 - data table */
lua_newtable
(
lua
);
/* arg2 - data table */
if
(
data
.
clid_len
!=
0
)
if
(
is6
)
{
lua_pushstring
(
lua
,
daemon
->
packet
);
lua_setfield
(
lua
,
-
2
,
"duid"
);
lua_pushstring
(
lua
,
daemon
->
dhcp_buff3
);
lua_setfield
(
lua
,
-
2
,
"iaid"
);
}
if
(
!
is6
&&
data
.
clid_len
!=
0
)
{
{
lua_pushstring
(
lua
,
daemon
->
packet
);
lua_pushstring
(
lua
,
daemon
->
packet
);
lua_setfield
(
lua
,
-
2
,
"client_id"
);
lua_setfield
(
lua
,
-
2
,
"client_id"
);
...
@@ -294,20 +342,36 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
...
@@ -294,20 +342,36 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
end
=
extradata
+
data
.
ed_len
;
end
=
extradata
+
data
.
ed_len
;
buf
=
extradata
;
buf
=
extradata
;
buf
=
grab_extradata_lua
(
buf
,
end
,
"vendor_class"
);
if
(
!
is6
)
buf
=
grab_extradata_lua
(
buf
,
end
,
"vendor_class"
);
#ifdef HAVE_DHCP6
else
for
(
i
=
0
;
i
<
data
.
hwaddr_len
;
i
++
)
{
sprintf
(
daemon
->
dhcp_buff2
,
"vendor_class%i"
,
i
);
buf
=
grab_extradata_lua
(
buf
,
end
,
daemon
->
dhcp_buff2
);
}
#endif
buf
=
grab_extradata_lua
(
buf
,
end
,
"supplied_hostname"
);
buf
=
grab_extradata_lua
(
buf
,
end
,
"supplied_hostname"
);
buf
=
grab_extradata_lua
(
buf
,
end
,
"cpewan_oui"
);
buf
=
grab_extradata_lua
(
buf
,
end
,
"cpewan_serial"
);
if
(
!
is6
)
buf
=
grab_extradata_lua
(
buf
,
end
,
"cpewan_class"
);
{
buf
=
grab_extradata_lua
(
buf
,
end
,
"cpewan_oui"
);
buf
=
grab_extradata_lua
(
buf
,
end
,
"cpewan_serial"
);
buf
=
grab_extradata_lua
(
buf
,
end
,
"cpewan_class"
);
}
buf
=
grab_extradata_lua
(
buf
,
end
,
"tags"
);
buf
=
grab_extradata_lua
(
buf
,
end
,
"tags"
);
for
(
i
=
0
;
buf
;
i
++
)
for
(
i
=
0
;
buf
;
i
++
)
{
{
sprintf
(
daemon
->
dhcp_buff2
,
"user_class%i"
,
i
);
sprintf
(
daemon
->
dhcp_buff2
,
"user_class%i"
,
i
);
buf
=
grab_extradata_lua
(
buf
,
end
,
daemon
->
dhcp_buff2
);
buf
=
grab_extradata_lua
(
buf
,
end
,
daemon
->
dhcp_buff2
);
}
}
if
(
data
.
giaddr
.
s_addr
!=
0
)
if
(
!
is6
&&
data
.
giaddr
.
s_addr
!=
0
)
{
{
lua_pushstring
(
lua
,
inet_ntoa
(
data
.
giaddr
));
lua_pushstring
(
lua
,
inet_ntoa
(
data
.
giaddr
));
lua_setfield
(
lua
,
-
2
,
"relay_address"
);
lua_setfield
(
lua
,
-
2
,
"relay_address"
);
...
@@ -325,10 +389,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
...
@@ -325,10 +389,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
lua_setfield
(
lua
,
-
2
,
"old_hostname"
);
lua_setfield
(
lua
,
-
2
,
"old_hostname"
);
}
}
lua_pushstring
(
lua
,
daemon
->
dhcp_buff
);
if
(
!
is6
)
lua_setfield
(
lua
,
-
2
,
"mac_address"
);
{
lua_pushstring
(
lua
,
daemon
->
dhcp_buff
);
lua_pushstring
(
lua
,
inet_ntoa
(
data
.
addr
));
lua_setfield
(
lua
,
-
2
,
"mac_address"
);
}
lua_pushstring
(
lua
,
daemon
->
addrbuff
);
lua_setfield
(
lua
,
-
2
,
"ip_address"
);
lua_setfield
(
lua
,
-
2
,
"ip_address"
);
lua_call
(
lua
,
2
,
0
);
/* pass 2 values, expect 0 */
lua_call
(
lua
,
2
,
0
);
/* pass 2 values, expect 0 */
...
@@ -372,7 +439,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
...
@@ -372,7 +439,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue
;
continue
;
}
}
if
(
data
.
clid_len
!=
0
)
if
(
is6
)
{
my_setenv
(
"DNSMASQ_IAID"
,
daemon
->
dhcp_buff3
,
&
err
);
my_setenv
(
"DNSMASQ_DUID"
,
daemon
->
packet
,
&
err
);
}
if
(
!
is6
&&
data
.
clid_len
!=
0
)
my_setenv
(
"DNSMASQ_CLIENT_ID"
,
daemon
->
packet
,
&
err
);
my_setenv
(
"DNSMASQ_CLIENT_ID"
,
daemon
->
packet
,
&
err
);
if
(
strlen
(
data
.
interface
)
!=
0
)
if
(
strlen
(
data
.
interface
)
!=
0
)
...
@@ -389,11 +462,33 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
...
@@ -389,11 +462,33 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
end
=
extradata
+
data
.
ed_len
;
end
=
extradata
+
data
.
ed_len
;
buf
=
extradata
;
buf
=
extradata
;
buf
=
grab_extradata
(
buf
,
end
,
"DNSMASQ_VENDOR_CLASS"
,
&
err
);
if
(
!
is6
)
buf
=
grab_extradata
(
buf
,
end
,
"DNSMASQ_VENDOR_CLASS"
,
&
err
);
#ifdef HAVE_DHCP6
else
{
if
(
data
.
hwaddr_len
!=
0
)
{
buf
=
grab_extradata
(
buf
,
end
,
"DNSMASQ_VENDOR_CLASS_ID"
,
&
err
);
for
(
i
=
0
;
i
<
data
.
hwaddr_len
-
1
;
i
++
)
{
sprintf
(
daemon
->
dhcp_buff2
,
"DNSMASQ_VENDOR_CLASS%i"
,
i
);
buf
=
grab_extradata
(
buf
,
end
,
daemon
->
dhcp_buff2
,
&
err
);
}
}
}
#endif
buf
=
grab_extradata
(
buf
,
end
,
"DNSMASQ_SUPPLIED_HOSTNAME"
,
&
err
);
buf
=
grab_extradata
(
buf
,
end
,
"DNSMASQ_SUPPLIED_HOSTNAME"
,
&
err
);
buf
=
grab_extradata
(
buf
,
end
,
"DNSMASQ_CPEWAN_OUI"
,
&
err
);
buf
=
grab_extradata
(
buf
,
end
,
"DNSMASQ_CPEWAN_SERIAL"
,
&
err
);
if
(
!
is6
)
buf
=
grab_extradata
(
buf
,
end
,
"DNSMASQ_CPEWAN_CLASS"
,
&
err
);
{
buf
=
grab_extradata
(
buf
,
end
,
"DNSMASQ_CPEWAN_OUI"
,
&
err
);
buf
=
grab_extradata
(
buf
,
end
,
"DNSMASQ_CPEWAN_SERIAL"
,
&
err
);
buf
=
grab_extradata
(
buf
,
end
,
"DNSMASQ_CPEWAN_CLASS"
,
&
err
);
}
buf
=
grab_extradata
(
buf
,
end
,
"DNSMASQ_TAGS"
,
&
err
);
buf
=
grab_extradata
(
buf
,
end
,
"DNSMASQ_TAGS"
,
&
err
);
for
(
i
=
0
;
buf
;
i
++
)
for
(
i
=
0
;
buf
;
i
++
)
...
@@ -402,7 +497,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
...
@@ -402,7 +497,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
buf
=
grab_extradata
(
buf
,
end
,
daemon
->
dhcp_buff2
,
&
err
);
buf
=
grab_extradata
(
buf
,
end
,
daemon
->
dhcp_buff2
,
&
err
);
}
}
if
(
data
.
giaddr
.
s_addr
!=
0
)
if
(
!
is6
&&
data
.
giaddr
.
s_addr
!=
0
)
my_setenv
(
"DNSMASQ_RELAY_ADDRESS"
,
inet_ntoa
(
data
.
giaddr
),
&
err
);
my_setenv
(
"DNSMASQ_RELAY_ADDRESS"
,
inet_ntoa
(
data
.
giaddr
),
&
err
);
if
(
data
.
action
!=
ACTION_DEL
&&
data
.
remaining_time
!=
0
)
if
(
data
.
action
!=
ACTION_DEL
&&
data
.
remaining_time
!=
0
)
...
@@ -427,7 +522,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
...
@@ -427,7 +522,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
{
{
execl
(
daemon
->
lease_change_command
,
execl
(
daemon
->
lease_change_command
,
p
?
p
+
1
:
daemon
->
lease_change_command
,
p
?
p
+
1
:
daemon
->
lease_change_command
,
action_str
,
daemon
->
dhcp_buff
,
inet_ntoa
(
data
.
addr
)
,
hostname
,
(
char
*
)
NULL
);
action_str
,
daemon
->
dhcp_buff
,
daemon
->
addrbuff
,
hostname
,
(
char
*
)
NULL
);
err
=
errno
;
err
=
errno
;
}
}
/* failed, send event so the main process logs the problem */
/* failed, send event so the main process logs the problem */
...
@@ -493,7 +588,13 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
...
@@ -493,7 +588,13 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
unsigned
char
*
p
;
unsigned
char
*
p
;
size_t
size
;
size_t
size
;
unsigned
int
hostname_len
=
0
,
clid_len
=
0
,
ed_len
=
0
;
unsigned
int
hostname_len
=
0
,
clid_len
=
0
,
ed_len
=
0
;
int
fd
=
daemon
->
dhcpfd
;
#ifdef HAVE_DHCP6
if
(
!
daemon
->
dhcp
)
fd
=
daemon
->
dhcp6fd
;
#endif
/* no script */
/* no script */
if
(
daemon
->
helperfd
==
-
1
)
if
(
daemon
->
helperfd
==
-
1
)
return
;
return
;
...
@@ -524,6 +625,7 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
...
@@ -524,6 +625,7 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
}
}
buf
->
action
=
action
;
buf
->
action
=
action
;
buf
->
flags
=
lease
->
flags
;
buf
->
hwaddr_len
=
lease
->
hwaddr_len
;
buf
->
hwaddr_len
=
lease
->
hwaddr_len
;
buf
->
hwaddr_type
=
lease
->
hwaddr_type
;
buf
->
hwaddr_type
=
lease
->
hwaddr_type
;
buf
->
clid_len
=
clid_len
;
buf
->
clid_len
=
clid_len
;
...
@@ -531,8 +633,8 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
...
@@ -531,8 +633,8 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
buf
->
hostname_len
=
hostname_len
;
buf
->
hostname_len
=
hostname_len
;
buf
->
addr
=
lease
->
addr
;
buf
->
addr
=
lease
->
addr
;
buf
->
giaddr
=
lease
->
giaddr
;
buf
->
giaddr
=
lease
->
giaddr
;
memcpy
(
buf
->
hwaddr
,
lease
->
hwaddr
,
lease
->
hwaddr_len
);
memcpy
(
buf
->
hwaddr
,
lease
->
hwaddr
,
DHCP_CHADDR_MAX
);
if
(
!
indextoname
(
daemon
->
dhcp
fd
,
lease
->
last_interface
,
buf
->
interface
))
if
(
!
indextoname
(
fd
,
lease
->
last_interface
,
buf
->
interface
))
buf
->
interface
[
0
]
=
0
;
buf
->
interface
[
0
]
=
0
;
#ifdef HAVE_BROKEN_RTC
#ifdef HAVE_BROKEN_RTC
...
...
src/lease.c
View file @
c6cc03ed
...
@@ -28,18 +28,9 @@ void lease_init(time_t now)
...
@@ -28,18 +28,9 @@ void lease_init(time_t now)
struct
dhcp_lease
*
lease
;
struct
dhcp_lease
*
lease
;
int
clid_len
,
hw_len
,
hw_type
;
int
clid_len
,
hw_len
,
hw_type
;
FILE
*
leasestream
;
FILE
*
leasestream
;
#ifdef HAVE_DHCP6
int
v6pass
=
0
;
#endif
/* These each hold a DHCP option max size 255
and get a terminating zero added */
daemon
->
dhcp_buff
=
safe_malloc
(
256
);
daemon
->
dhcp_buff2
=
safe_malloc
(
256
);
daemon
->
dhcp_buff3
=
safe_malloc
(
256
);
leases_left
=
daemon
->
dhcp_max
;
leases_left
=
daemon
->
dhcp_max
;
if
(
option_bool
(
OPT_LEASE_RO
))
if
(
option_bool
(
OPT_LEASE_RO
))
{
{
/* run "<lease_change_script> init" once to get the
/* run "<lease_change_script> init" once to get the
...
@@ -73,47 +64,70 @@ void lease_init(time_t now)
...
@@ -73,47 +64,70 @@ void lease_init(time_t now)
rewind
(
leasestream
);
rewind
(
leasestream
);
}
}
#ifdef HAVE_DHCP6
again:
#endif
/* client-id max length is 255 which is 255*2 digits + 254 colons
/* client-id max length is 255 which is 255*2 digits + 254 colons
borrow DNS packet buffer which is always larger than 1000 bytes */
borrow DNS packet buffer which is always larger than 1000 bytes */
if
(
leasestream
)
if
(
leasestream
)
while
(
fscanf
(
leasestream
,
"%lu %255s %64s %255s %764s"
,
while
(
fscanf
(
leasestream
,
"%255s %255s"
,
daemon
->
dhcp_buff3
,
daemon
->
dhcp_buff2
)
==
2
)
&
ei
,
daemon
->
dhcp_buff2
,
daemon
->
namebuff
,
daemon
->
dhcp_buff
,
daemon
->
packet
)
==
5
)
{
{
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
if
(
v6pass
)
if
(
strcmp
(
daemon
->
dhcp_buff3
,
"duid"
)
==
0
)
hw_type
=
atoi
(
daemon
->
dhcp_buff2
);
else
#endif
{
{
hw_len
=
parse_hex
(
daemon
->
dhcp_buff2
,
(
unsigned
char
*
)
daemon
->
dhcp_buff2
,
DHCP_CHADDR_MAX
,
NULL
,
&
hw_type
);
daemon
->
duid_len
=
parse_hex
(
daemon
->
dhcp_buff2
,
(
unsigned
char
*
)
daemon
->
dhcp_buff2
,
130
,
NULL
,
NULL
);
/* For backwards compatibility, no explict MAC address type means ether. */
daemon
->
duid
=
safe_malloc
(
daemon
->
duid_len
);
if
(
hw_type
==
0
&&
hw_len
!=
0
)
memcpy
(
daemon
->
duid
,
daemon
->
dhcp_buff2
,
daemon
->
duid_len
);
hw_type
=
ARPHRD_ETHER
;
continue
;
}
}
#endif
#ifdef HAVE_DHCP6
ei
=
atol
(
daemon
->
dhcp_buff3
);
if
(
v6pass
)
inet_pton
(
AF_INET6
,
daemon
->
namebuff
,
&
addr
.
addr
.
addr6
);
if
(
fscanf
(
leasestream
,
" %64s %255s %764s"
,
else
daemon
->
namebuff
,
daemon
->
dhcp_buff
,
daemon
->
packet
)
!=
3
)
#endif
break
;
inet_pton
(
AF_INET
,
daemon
->
namebuff
,
&
addr
.
addr
.
addr4
);
clid_len
=
0
;
clid_len
=
0
;
if
(
strcmp
(
daemon
->
packet
,
"*"
)
!=
0
)
if
(
strcmp
(
daemon
->
packet
,
"*"
)
!=
0
)
clid_len
=
parse_hex
(
daemon
->
packet
,
(
unsigned
char
*
)
daemon
->
packet
,
255
,
NULL
,
NULL
);
clid_len
=
parse_hex
(
daemon
->
packet
,
(
unsigned
char
*
)
daemon
->
packet
,
255
,
NULL
,
NULL
);
if
(
inet_pton
(
AF_INET
,
daemon
->
namebuff
,
&
addr
.
addr
.
addr4
)
&&
(
lease
=
lease4_allocate
(
addr
.
addr
.
addr4
)))
{
hw_len
=
parse_hex
(
daemon
->
dhcp_buff2
,
(
unsigned
char
*
)
daemon
->
dhcp_buff2
,
DHCP_CHADDR_MAX
,
NULL
,
&
hw_type
);
/* For backwards compatibility, no explict MAC address type means ether. */
if
(
hw_type
==
0
&&
hw_len
!=
0
)
hw_type
=
ARPHRD_ETHER
;
lease_set_hwaddr
(
lease
,
(
unsigned
char
*
)
daemon
->
dhcp_buff2
,
(
unsigned
char
*
)
daemon
->
packet
,
hw_len
,
hw_type
,
clid_len
);
if
(
strcmp
(
daemon
->
dhcp_buff
,
"*"
)
!=
0
)
lease_set_hostname
(
lease
,
daemon
->
dhcp_buff
,
0
,
get_domain
(
lease
->
addr
),
NULL
);
}
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
if
(
v6pass
)
else
if
(
inet_pton
(
AF_INET6
,
daemon
->
namebuff
,
&
addr
.
addr
.
addr6
))
lease
=
lease6_allocate
(
&
addr
.
addr
.
addr6
);
{
else
char
*
s
=
daemon
->
dhcp_buff2
;
int
lease_type
=
LEASE_NA
;
if
(
s
[
0
]
==
'T'
)
{
lease_type
=
LEASE_TA
;
s
++
;
}
hw_type
=
atoi
(
s
);
if
((
lease
=
lease6_allocate
(
&
addr
.
addr
.
addr6
,
lease_type
)))
{
lease_set_hwaddr
(
lease
,
NULL
,
(
unsigned
char
*
)
daemon
->
packet
,
0
,
hw_type
,
clid_len
);
if
(
strcmp
(
daemon
->
dhcp_buff
,
"*"
)
!=
0
)
lease_set_hostname
(
lease
,
daemon
->
dhcp_buff
,
0
,
get_domain6
((
struct
in6_addr
*
)
lease
->
hwaddr
),
NULL
);
}
}
#endif
#endif
lease
=
lease4_allocate
(
addr
.
addr
.
addr4
);
else
break
;
if
(
!
lease
)
if
(
!
lease
)
die
(
_
(
"too many stored leases"
),
NULL
,
EC_MISC
);
die
(
_
(
"too many stored leases"
),
NULL
,
EC_MISC
);
...
@@ -128,36 +142,16 @@ void lease_init(time_t now)
...
@@ -128,36 +142,16 @@ void lease_init(time_t now)
even when sizeof(time_t) == 8 */
even when sizeof(time_t) == 8 */
lease
->
expires
=
(
time_t
)
ei
;
lease
->
expires
=
(
time_t
)
ei
;
#endif
#endif
#ifdef HAVE_DHCP6
if
(
!
v6pass
)
#endif
lease_set_hwaddr
(
lease
,
(
unsigned
char
*
)
daemon
->
dhcp_buff2
,
(
unsigned
char
*
)
daemon
->
packet
,
hw_len
,
hw_type
,
clid_len
);
if
(
strcmp
(
daemon
->
dhcp_buff
,
"*"
)
!=
0
)
lease_set_hostname
(
lease
,
daemon
->
dhcp_buff
,
0
);
/* set these correctly: the "old" events are generated later from
/* set these correctly: the "old" events are generated later from
the startup synthesised SIGHUP. */
the startup synthesised SIGHUP. */
lease
->
new
=
lease
->
changed
=
0
;
lease
->
flags
&=
~
(
LEASE_NEW
|
LEASE_CHANGED
)
;
}
}
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
if
(
!
v6pass
)
/* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
{
if
(
!
daemon
->
duid
&&
daemon
->
dhcp6
)
if
(
fscanf
(
leasestream
,
"duid %255s"
,
daemon
->
dhcp_buff
)
==
1
)
make_duid
(
now
);
{
daemon
->
duid_len
=
parse_hex
(
daemon
->
dhcp_buff
,
(
unsigned
char
*
)
daemon
->
dhcp_buff
,
130
,
NULL
,
NULL
);
daemon
->
duid
=
safe_malloc
(
daemon
->
duid_len
);
memcpy
(
daemon
->
duid
,
daemon
->
dhcp_buff
,
daemon
->
duid_len
);
v6pass
=
1
;
goto
again
;
}
/* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
if
(
daemon
->
dhcp6
)
make_duid
(
now
);
}
#endif
#endif
#ifdef HAVE_SCRIPT
#ifdef HAVE_SCRIPT
...
@@ -196,17 +190,17 @@ void lease_update_from_configs(void)
...
@@ -196,17 +190,17 @@ void lease_update_from_configs(void)
struct
dhcp_lease
*
lease
;
struct
dhcp_lease
*
lease
;
struct
dhcp_config
*
config
;
struct
dhcp_config
*
config
;
char
*
name
;
char
*
name
;
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
if
((
config
=
find_config
(
daemon
->
dhcp_conf
,
NULL
,
lease
->
clid
,
lease
->
clid_len
,
if
((
config
=
find_config
(
daemon
->
dhcp_conf
,
NULL
,
lease
->
clid
,
lease
->
clid_len
,
lease
->
hwaddr
,
lease
->
hwaddr_len
,
lease
->
hwaddr_type
,
NULL
))
&&
lease
->
hwaddr
,
lease
->
hwaddr_len
,
lease
->
hwaddr_type
,
NULL
))
&&
(
config
->
flags
&
CONFIG_NAME
)
&&
(
config
->
flags
&
CONFIG_NAME
)
&&
(
!
(
config
->
flags
&
CONFIG_ADDR
)
||
config
->
addr
.
s_addr
==
lease
->
addr
.
s_addr
))
(
!
(
config
->
flags
&
CONFIG_ADDR
)
||
config
->
addr
.
s_addr
==
lease
->
addr
.
s_addr
))
lease_set_hostname
(
lease
,
config
->
hostname
,
1
);
lease_set_hostname
(
lease
,
config
->
hostname
,
1
,
get_domain
(
lease
->
addr
),
NULL
);
else
if
((
name
=
host_from_dns
(
lease
->
addr
)))
else
if
((
name
=
host_from_dns
(
lease
->
addr
)))
lease_set_hostname
(
lease
,
name
,
1
);
/* updates auth flag only */
lease_set_hostname
(
lease
,
name
,
1
,
get_domain
(
lease
->
addr
),
NULL
);
/* updates auth flag only */
}
}
static
void
ourprintf
(
int
*
errp
,
char
*
format
,
...)
static
void
ourprintf
(
int
*
errp
,
char
*
format
,
...)
{
{
va_list
ap
;
va_list
ap
;
...
@@ -234,7 +228,7 @@ void lease_update_file(time_t now)
...
@@ -234,7 +228,7 @@ void lease_update_file(time_t now)
{
{
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
if
(
lease
->
is_ipv6
)
if
(
lease
->
flags
&
(
LEASE_TA
|
LEASE_NA
)
)
continue
;
continue
;
#endif
#endif
...
@@ -279,7 +273,7 @@ void lease_update_file(time_t now)
...
@@ -279,7 +273,7 @@ void lease_update_file(time_t now)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
{
{
if
(
!
lease
->
is_ipv6
)
if
(
!
(
lease
->
flags
&
(
LEASE_TA
|
LEASE_NA
))
)
continue
;
continue
;
#ifdef HAVE_BROKEN_RTC
#ifdef HAVE_BROKEN_RTC
...
@@ -290,7 +284,8 @@ void lease_update_file(time_t now)
...
@@ -290,7 +284,8 @@ void lease_update_file(time_t now)
inet_ntop
(
AF_INET6
,
lease
->
hwaddr
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
inet_ntop
(
AF_INET6
,
lease
->
hwaddr
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
ourprintf
(
&
err
,
"%u %s "
,
lease
->
hwaddr_type
,
daemon
->
addrbuff
);
ourprintf
(
&
err
,
"%s%u %s "
,
(
lease
->
flags
&
LEASE_TA
)
?
"T"
:
""
,
lease
->
hwaddr_type
,
daemon
->
addrbuff
);
ourprintf
(
&
err
,
"%s "
,
lease
->
hostname
?
lease
->
hostname
:
"*"
);
ourprintf
(
&
err
,
"%s "
,
lease
->
hostname
?
lease
->
hostname
:
"*"
);
if
(
lease
->
clid
&&
lease
->
clid_len
!=
0
)
if
(
lease
->
clid
&&
lease
->
clid_len
!=
0
)
...
@@ -343,11 +338,21 @@ void lease_update_dns(void)
...
@@ -343,11 +338,21 @@ void lease_update_dns(void)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
{
{
int
prot
=
AF_INET
;
#ifdef HAVE_DHCP6
if
(
lease
->
flags
&
(
LEASE_TA
|
LEASE_NA
))
prot
=
AF_INET6
;
#endif
if
(
lease
->
fqdn
)
if
(
lease
->
fqdn
)
cache_add_dhcp_entry
(
lease
->
fqdn
,
&
lease
->
addr
,
lease
->
expires
);
cache_add_dhcp_entry
(
lease
->
fqdn
,
prot
,
prot
==
AF_INET
?
(
struct
all_addr
*
)
&
lease
->
addr
:
(
struct
all_addr
*
)
&
lease
->
hwaddr
,
lease
->
expires
);
if
(
!
option_bool
(
OPT_DHCP_FQDN
)
&&
lease
->
hostname
)
if
(
!
option_bool
(
OPT_DHCP_FQDN
)
&&
lease
->
hostname
)
cache_add_dhcp_entry
(
lease
->
hostname
,
&
lease
->
addr
,
lease
->
expires
);
cache_add_dhcp_entry
(
lease
->
hostname
,
prot
,
prot
==
AF_INET
?
(
struct
all_addr
*
)
&
lease
->
addr
:
(
struct
all_addr
*
)
&
lease
->
hwaddr
,
lease
->
expires
);
}
}
dns_dirty
=
0
;
dns_dirty
=
0
;
...
@@ -391,7 +396,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
...
@@ -391,7 +396,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
{
{
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
if
(
lease
->
is_ipv6
)
if
(
lease
->
flags
&
(
LEASE_TA
|
LEASE_NA
)
)
continue
;
continue
;
#endif
#endif
if
(
lease
->
clid
&&
clid_len
==
lease
->
clid_len
&&
if
(
lease
->
clid
&&
clid_len
==
lease
->
clid_len
&&
...
@@ -402,7 +407,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
...
@@ -402,7 +407,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
{
{
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
if
(
lease
->
is_ipv6
)
if
(
lease
->
flags
&
(
LEASE_TA
|
LEASE_NA
)
)
continue
;
continue
;
#endif
#endif
if
((
!
lease
->
clid
||
!
clid
)
&&
if
((
!
lease
->
clid
||
!
clid
)
&&
...
@@ -423,7 +428,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
...
@@ -423,7 +428,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
{
{
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
if
(
lease
->
is_ipv6
)
if
(
lease
->
flags
&
(
LEASE_TA
|
LEASE_NA
)
)
continue
;
continue
;
#endif
#endif
if
(
lease
->
addr
.
s_addr
==
addr
.
s_addr
)
if
(
lease
->
addr
.
s_addr
==
addr
.
s_addr
)
...
@@ -434,19 +439,36 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
...
@@ -434,19 +439,36 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
}
}
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
struct
dhcp_lease
*
lease6_find_by_client
(
unsigned
char
*
clid
,
int
clid_len
,
int
iaid
)
/* addr or clid may be NULL for "don't care, both NULL resets "USED" flags both
set activates USED check */
struct
dhcp_lease
*
lease6_find
(
unsigned
char
*
clid
,
int
clid_len
,
int
lease_type
,
int
iaid
,
struct
in6_addr
*
addr
)
{
{
struct
dhcp_lease
*
lease
;
struct
dhcp_lease
*
lease
;
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
{
{
if
(
!
lease
->
is_ipv6
)
if
(
!
(
lease
->
flags
&
lease_type
)
||
lease
->
hwaddr_type
!=
iaid
)
continue
;
continue
;
if
(
lease
->
hwaddr_type
==
iaid
&&
if
(
clid
&&
addr
&&
(
lease
->
flags
&
LEASE_USED
))
lease
->
clid
&&
clid_len
==
lease
->
clid_len
&&
continue
;
memcmp
(
clid
,
lease
->
clid
,
clid_len
)
==
0
)
return
lease
;
if
(
addr
&&
memcmp
(
lease
->
hwaddr
,
addr
,
IN6ADDRSZ
)
!=
0
)
continue
;
if
(
clid
&&
(
clid_len
!=
lease
->
clid_len
||
memcmp
(
clid
,
lease
->
clid
,
clid_len
)
!=
0
))
continue
;
if
(
clid
||
addr
)
{
lease
->
flags
|=
LEASE_USED
;
return
lease
;
}
else
lease
->
flags
&=
~
LEASE_USED
;
}
}
return
NULL
;
return
NULL
;
...
@@ -455,12 +477,12 @@ struct dhcp_lease *lease6_find_by_client(unsigned char *clid, int clid_len, int
...
@@ -455,12 +477,12 @@ struct dhcp_lease *lease6_find_by_client(unsigned char *clid, int clid_len, int
struct
dhcp_lease
*
lease6_find_by_addr
(
struct
in6_addr
*
net
,
int
prefix
,
u64
addr
)
struct
dhcp_lease
*
lease6_find_by_addr
(
struct
in6_addr
*
net
,
int
prefix
,
u64
addr
)
{
{
struct
dhcp_lease
*
lease
;
struct
dhcp_lease
*
lease
;
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
{
{
if
(
!
lease
->
is_ipv6
)
if
(
!
(
lease
->
flags
&
(
LEASE_TA
|
LEASE_NA
))
)
continue
;
continue
;
if
(
is_same_net6
((
struct
in6_addr
*
)
lease
->
hwaddr
,
net
,
prefix
)
&&
if
(
is_same_net6
((
struct
in6_addr
*
)
lease
->
hwaddr
,
net
,
prefix
)
&&
(
prefix
==
128
||
addr6part
((
struct
in6_addr
*
)
lease
->
hwaddr
)
==
addr
))
(
prefix
==
128
||
addr6part
((
struct
in6_addr
*
)
lease
->
hwaddr
)
==
addr
))
return
lease
;
return
lease
;
...
@@ -468,7 +490,6 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add
...
@@ -468,7 +490,6 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add
return
NULL
;
return
NULL
;
}
}
#endif
#endif
/* Find largest assigned address in context */
/* Find largest assigned address in context */
...
@@ -481,7 +502,7 @@ struct in_addr lease_find_max_addr(struct dhcp_context *context)
...
@@ -481,7 +502,7 @@ struct in_addr lease_find_max_addr(struct dhcp_context *context)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
{
{
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
if
(
lease
->
is_ipv6
)
if
(
lease
->
flags
&
(
LEASE_TA
|
LEASE_NA
)
)
continue
;
continue
;
#endif
#endif
if
(((
unsigned
)
ntohl
(
lease
->
addr
.
s_addr
))
>
((
unsigned
)
ntohl
(
context
->
start
.
s_addr
))
&&
if
(((
unsigned
)
ntohl
(
lease
->
addr
.
s_addr
))
>
((
unsigned
)
ntohl
(
context
->
start
.
s_addr
))
&&
...
@@ -500,7 +521,7 @@ static struct dhcp_lease *lease_allocate(void)
...
@@ -500,7 +521,7 @@ static struct dhcp_lease *lease_allocate(void)
return
NULL
;
return
NULL
;
memset
(
lease
,
0
,
sizeof
(
struct
dhcp_lease
));
memset
(
lease
,
0
,
sizeof
(
struct
dhcp_lease
));
lease
->
new
=
1
;
lease
->
flags
=
LEASE_NEW
;
lease
->
expires
=
1
;
lease
->
expires
=
1
;
#ifdef HAVE_BROKEN_RTC
#ifdef HAVE_BROKEN_RTC
lease
->
length
=
0xffffffff
;
/* illegal value */
lease
->
length
=
0xffffffff
;
/* illegal value */
...
@@ -524,11 +545,11 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
...
@@ -524,11 +545,11 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
}
}
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
struct
dhcp_lease
*
lease6_allocate
(
struct
in6_addr
*
addrp
)
struct
dhcp_lease
*
lease6_allocate
(
struct
in6_addr
*
addrp
,
int
lease_type
)
{
{
struct
dhcp_lease
*
lease
=
lease_allocate
();
struct
dhcp_lease
*
lease
=
lease_allocate
();
memcpy
(
lease
->
hwaddr
,
addrp
,
sizeof
(
*
addrp
))
;
memcpy
(
lease
->
hwaddr
,
addrp
,
sizeof
(
*
addrp
))
;
lease
->
is_ipv6
=
1
;
lease
->
flags
|=
lease_type
;
return
lease
;
return
lease
;
}
}
...
@@ -549,7 +570,8 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
...
@@ -549,7 +570,8 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
dns_dirty
=
1
;
dns_dirty
=
1
;
lease
->
expires
=
exp
;
lease
->
expires
=
exp
;
#ifndef HAVE_BROKEN_RTC
#ifndef HAVE_BROKEN_RTC
lease
->
aux_changed
=
file_dirty
=
1
;
lease
->
flags
|=
LEASE_AUX_CHANGED
;
file_dirty
=
1
;
#endif
#endif
}
}
...
@@ -569,10 +591,12 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
...
@@ -569,10 +591,12 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
hw_type
!=
lease
->
hwaddr_type
||
hw_type
!=
lease
->
hwaddr_type
||
(
hw_len
!=
0
&&
memcmp
(
lease
->
hwaddr
,
hwaddr
,
hw_len
)
!=
0
))
(
hw_len
!=
0
&&
memcmp
(
lease
->
hwaddr
,
hwaddr
,
hw_len
)
!=
0
))
{
{
memcpy
(
lease
->
hwaddr
,
hwaddr
,
hw_len
);
if
(
hw_len
!=
0
)
memcpy
(
lease
->
hwaddr
,
hwaddr
,
hw_len
);
lease
->
hwaddr_len
=
hw_len
;
lease
->
hwaddr_len
=
hw_len
;
lease
->
hwaddr_type
=
hw_type
;
lease
->
hwaddr_type
=
hw_type
;
lease
->
changed
=
file_dirty
=
1
;
/* run script on change */
lease
->
flags
|=
LEASE_CHANGED
;
file_dirty
=
1
;
/* run script on change */
}
}
/* only update clid when one is available, stops packets
/* only update clid when one is available, stops packets
...
@@ -585,14 +609,18 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
...
@@ -585,14 +609,18 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
if
(
lease
->
clid_len
!=
clid_len
)
if
(
lease
->
clid_len
!=
clid_len
)
{
{
lease
->
aux_changed
=
file_dirty
=
1
;
lease
->
flags
|=
LEASE_AUX_CHANGED
;
file_dirty
=
1
;
free
(
lease
->
clid
);
free
(
lease
->
clid
);
if
(
!
(
lease
->
clid
=
whine_malloc
(
clid_len
)))
if
(
!
(
lease
->
clid
=
whine_malloc
(
clid_len
)))
return
;
return
;
}
}
else
if
(
memcmp
(
lease
->
clid
,
clid
,
clid_len
)
!=
0
)
else
if
(
memcmp
(
lease
->
clid
,
clid
,
clid_len
)
!=
0
)
lease
->
aux_changed
=
file_dirty
=
1
;
{
lease
->
flags
|=
LEASE_AUX_CHANGED
;
file_dirty
=
1
;
}
lease
->
clid_len
=
clid_len
;
lease
->
clid_len
=
clid_len
;
memcpy
(
lease
->
clid
,
clid
,
clid_len
);
memcpy
(
lease
->
clid
,
clid
,
clid_len
);
}
}
...
@@ -608,7 +636,7 @@ static void kill_name(struct dhcp_lease *lease)
...
@@ -608,7 +636,7 @@ static void kill_name(struct dhcp_lease *lease)
free
(
lease
->
old_hostname
);
free
(
lease
->
old_hostname
);
/* If we know the fqdn, pass that. The helper will derive the
/* If we know the fqdn, pass that. The helper will derive the
unqualified name from it, free the unqu
la
ified name here. */
unqualified name from it, free the unqu
al
ified name here. */
if
(
lease
->
fqdn
)
if
(
lease
->
fqdn
)
{
{
...
@@ -621,14 +649,18 @@ static void kill_name(struct dhcp_lease *lease)
...
@@ -621,14 +649,18 @@ static void kill_name(struct dhcp_lease *lease)
lease
->
hostname
=
lease
->
fqdn
=
NULL
;
lease
->
hostname
=
lease
->
fqdn
=
NULL
;
}
}
void
lease_set_hostname
(
struct
dhcp_lease
*
lease
,
char
*
name
,
int
auth
)
void
lease_set_hostname
(
struct
dhcp_lease
*
lease
,
char
*
name
,
int
auth
,
char
*
domain
,
char
*
config_domain
)
{
{
struct
dhcp_lease
*
lease_tmp
;
struct
dhcp_lease
*
lease_tmp
;
char
*
new_name
=
NULL
,
*
new_fqdn
=
NULL
;
char
*
new_name
=
NULL
,
*
new_fqdn
=
NULL
;
if
(
config_domain
&&
(
!
domain
||
!
hostname_isequal
(
domain
,
config_domain
)))
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"Ignoring domain %s for DHCP host name %s"
),
config_domain
,
name
);
if
(
lease
->
hostname
&&
name
&&
hostname_isequal
(
lease
->
hostname
,
name
))
if
(
lease
->
hostname
&&
name
&&
hostname_isequal
(
lease
->
hostname
,
name
))
{
{
lease
->
auth_name
=
auth
;
if
(
auth
)
lease
->
flags
|=
LEASE_AUTH_NAME
;
return
;
return
;
}
}
...
@@ -638,19 +670,21 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
...
@@ -638,19 +670,21 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
/* If a machine turns up on a new net without dropping the old lease,
/* If a machine turns up on a new net without dropping the old lease,
or two machines claim the same name, then we end up with two interfaces with
or two machines claim the same name, then we end up with two interfaces with
the same name. Check for that here and remove the name from the old lease.
the same name. Check for that here and remove the name from the old lease.
Note that IPv6 leases are different. All the leases to the same DUID are
allowed the same name.
Don't allow a name from the client to override a name from dnsmasq config. */
Don't allow a name from the client to override a name from dnsmasq config. */
if
(
name
)
if
(
name
)
{
{
if
((
new_name
=
whine_malloc
(
strlen
(
name
)
+
1
)))
if
((
new_name
=
whine_malloc
(
strlen
(
name
)
+
1
)))
{
{
char
*
suffix
=
get_domain
(
lease
->
addr
);
strcpy
(
new_name
,
name
);
strcpy
(
new_name
,
name
);
if
(
suffix
&&
(
new_fqdn
=
whine_malloc
(
strlen
(
new_name
)
+
strlen
(
suffix
)
+
2
)))
if
(
domain
&&
(
new_fqdn
=
whine_malloc
(
strlen
(
new_name
)
+
strlen
(
domain
)
+
2
)))
{
{
strcpy
(
new_fqdn
,
name
);
strcpy
(
new_fqdn
,
name
);
strcat
(
new_fqdn
,
"."
);
strcat
(
new_fqdn
,
"."
);
strcat
(
new_fqdn
,
suffix
);
strcat
(
new_fqdn
,
domain
);
}
}
}
}
...
@@ -659,7 +693,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
...
@@ -659,7 +693,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
{
{
if
(
option_bool
(
OPT_DHCP_FQDN
))
if
(
option_bool
(
OPT_DHCP_FQDN
))
{
{
if
(
!
new_fqdn
||
!
lease_tmp
->
fqdn
||
!
hostname_isequal
(
lease_tmp
->
fqdn
,
new_fqdn
)
)
if
(
!
new_fqdn
||
!
lease_tmp
->
fqdn
||
!
hostname_isequal
(
lease_tmp
->
fqdn
,
new_fqdn
))
continue
;
continue
;
}
}
else
else
...
@@ -667,8 +701,22 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
...
@@ -667,8 +701,22 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
if
(
!
new_name
||
!
lease_tmp
->
hostname
||
!
hostname_isequal
(
lease_tmp
->
hostname
,
new_name
)
)
if
(
!
new_name
||
!
lease_tmp
->
hostname
||
!
hostname_isequal
(
lease_tmp
->
hostname
,
new_name
)
)
continue
;
continue
;
}
}
if
(
lease_tmp
->
auth_name
&&
!
auth
)
if
(
lease
->
flags
&
(
LEASE_TA
|
LEASE_NA
))
{
if
(
!
(
lease_tmp
->
flags
&
(
LEASE_TA
|
LEASE_NA
)))
continue
;
/* another lease for the same DUID is OK for IPv6 */
if
(
lease
->
clid_len
==
lease_tmp
->
clid_len
&&
lease
->
clid
&&
lease_tmp
->
clid
&&
memcmp
(
lease
->
clid
,
lease_tmp
->
clid
,
lease
->
clid_len
)
==
0
)
continue
;
}
else
if
(
lease_tmp
->
flags
&
(
LEASE_TA
|
LEASE_NA
))
continue
;
if
((
lease_tmp
->
flags
&
LEASE_AUTH_NAME
)
&&
!
auth
)
{
{
free
(
new_name
);
free
(
new_name
);
free
(
new_fqdn
);
free
(
new_fqdn
);
...
@@ -685,11 +733,13 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
...
@@ -685,11 +733,13 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
lease
->
hostname
=
new_name
;
lease
->
hostname
=
new_name
;
lease
->
fqdn
=
new_fqdn
;
lease
->
fqdn
=
new_fqdn
;
lease
->
auth_name
=
auth
;
if
(
auth
)
lease
->
flags
|=
LEASE_AUTH_NAME
;
file_dirty
=
1
;
file_dirty
=
1
;
dns_dirty
=
1
;
dns_dirty
=
1
;
lease
->
changed
=
1
;
/* run script on change */
lease
->
flags
|=
LEASE_CHANGED
;
/* run script on change */
}
}
void
lease_set_interface
(
struct
dhcp_lease
*
lease
,
int
interface
)
void
lease_set_interface
(
struct
dhcp_lease
*
lease
,
int
interface
)
...
@@ -698,7 +748,7 @@ void lease_set_interface(struct dhcp_lease *lease, int interface)
...
@@ -698,7 +748,7 @@ void lease_set_interface(struct dhcp_lease *lease, int interface)
return
;
return
;
lease
->
last_interface
=
interface
;
lease
->
last_interface
=
interface
;
lease
->
changed
=
1
;
lease
->
flags
|=
LEASE_CHANGED
;
}
}
void
rerun_scripts
(
void
)
void
rerun_scripts
(
void
)
...
@@ -706,7 +756,7 @@ void rerun_scripts(void)
...
@@ -706,7 +756,7 @@ void rerun_scripts(void)
struct
dhcp_lease
*
lease
;
struct
dhcp_lease
*
lease
;
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
lease
->
changed
=
1
;
lease
->
flags
|=
LEASE_CHANGED
;
}
}
/* deleted leases get transferred to the old_leases list.
/* deleted leases get transferred to the old_leases list.
...
@@ -772,18 +822,18 @@ int do_script_run(time_t now)
...
@@ -772,18 +822,18 @@ int do_script_run(time_t now)
}
}
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
for
(
lease
=
leases
;
lease
;
lease
=
lease
->
next
)
if
(
lease
->
new
||
lease
->
changed
||
if
(
(
lease
->
flags
&
(
LEASE_NEW
|
LEASE_CHANGED
))
||
(
lease
->
aux_changed
&&
option_bool
(
OPT_LEASE_RO
)))
(
(
lease
->
flags
&
LEASE_AUX_CHANGED
)
&&
option_bool
(
OPT_LEASE_RO
)))
{
{
#ifdef HAVE_SCRIPT
#ifdef HAVE_SCRIPT
queue_script
(
lease
->
new
?
ACTION_ADD
:
ACTION_OLD
,
lease
,
queue_script
(
(
lease
->
flags
&
LEASE_NEW
)
?
ACTION_ADD
:
ACTION_OLD
,
lease
,
lease
->
fqdn
?
lease
->
fqdn
:
lease
->
hostname
,
now
);
lease
->
fqdn
?
lease
->
fqdn
:
lease
->
hostname
,
now
);
#endif
#endif
#ifdef HAVE_DBUS
#ifdef HAVE_DBUS
emit_dbus_signal
(
lease
->
new
?
ACTION_ADD
:
ACTION_OLD
,
lease
,
emit_dbus_signal
(
(
lease
->
flags
&
LEASE_NEW
)
?
ACTION_ADD
:
ACTION_OLD
,
lease
,
lease
->
fqdn
?
lease
->
fqdn
:
lease
->
hostname
);
lease
->
fqdn
?
lease
->
fqdn
:
lease
->
hostname
);
#endif
#endif
lease
->
new
=
lease
->
changed
=
lease
->
aux_changed
=
0
;
lease
->
flags
&=
~
(
LEASE_NEW
|
LEASE_CHANGED
|
LEASE_AUX_CHANGED
)
;
/* this is used for the "add" call, then junked, since they're not in the database */
/* this is used for the "add" call, then junked, since they're not in the database */
free
(
lease
->
extradata
);
free
(
lease
->
extradata
);
...
@@ -795,6 +845,44 @@ int do_script_run(time_t now)
...
@@ -795,6 +845,44 @@ int do_script_run(time_t now)
return
0
;
/* nothing to do */
return
0
;
/* nothing to do */
}
}
#ifdef HAVE_SCRIPT
void
lease_add_extradata
(
struct
dhcp_lease
*
lease
,
unsigned
char
*
data
,
unsigned
int
len
,
int
delim
)
{
unsigned
int
i
;
/* check for embeded NULLs */
for
(
i
=
0
;
i
<
len
;
i
++
)
if
(
data
[
i
]
==
0
)
{
len
=
i
;
break
;
}
if
((
lease
->
extradata_size
-
lease
->
extradata_len
)
<
(
len
+
1
))
{
size_t
newsz
=
lease
->
extradata_len
+
len
+
100
;
unsigned
char
*
new
=
whine_malloc
(
newsz
);
if
(
!
new
)
return
;
if
(
lease
->
extradata
)
{
memcpy
(
new
,
lease
->
extradata
,
lease
->
extradata_len
);
free
(
lease
->
extradata
);
}
lease
->
extradata
=
new
;
lease
->
extradata_size
=
newsz
;
}
if
(
len
!=
0
)
memcpy
(
lease
->
extradata
+
lease
->
extradata_len
,
data
,
len
);
lease
->
extradata
[
lease
->
extradata_len
+
len
]
=
delim
;
lease
->
extradata_len
+=
len
+
1
;
}
#endif
#endif
#endif
...
...
src/netlink.c
View file @
c6cc03ed
...
@@ -282,7 +282,9 @@ int iface_enumerate(int family, void *parm, int (*callback)())
...
@@ -282,7 +282,9 @@ int iface_enumerate(int family, void *parm, int (*callback)())
rta
=
RTA_NEXT
(
rta
,
len1
);
rta
=
RTA_NEXT
(
rta
,
len1
);
}
}
if
(
mac
&&
!
((
*
callback
)(
link
->
ifi_type
,
link
->
ifi_flags
,
mac
,
maclen
,
parm
)))
if
(
mac
&&
!
((
*
callback
)((
unsigned
int
)
link
->
ifi_type
,
(
unsigned
int
)
link
->
ifi_flags
,
mac
,
maclen
,
parm
)))
return
0
;
return
0
;
}
}
#endif
#endif
...
...
src/option.c
View file @
c6cc03ed
...
@@ -363,15 +363,16 @@ static struct {
...
@@ -363,15 +363,16 @@ static struct {
};
};
#ifdef HAVE_DHCP
#ifdef HAVE_DHCP
#define OT_ADDR_LIST 0x80
#define OT_RFC1035_NAME 0x40
#define OT_INTERNAL 0x20
#define OT_NAME 0x10
#define OT_ADDR_LIST 0x8000
#define OT_RFC1035_NAME 0x4000
#define OT_INTERNAL 0x2000
#define OT_NAME 0x1000
#define OT_CSTRING 0x0800
static
const
struct
{
static
const
struct
opttab_t
{
char
*
name
;
char
*
name
;
u
nsigned
char
val
,
size
;
u
16
val
,
size
;
}
opttab
[]
=
{
}
opttab
[]
=
{
{
"netmask"
,
1
,
OT_ADDR_LIST
},
{
"netmask"
,
1
,
OT_ADDR_LIST
},
{
"time-offset"
,
2
,
4
},
{
"time-offset"
,
2
,
4
},
...
@@ -422,7 +423,7 @@ static const struct {
...
@@ -422,7 +423,7 @@ static const struct {
{
"T1"
,
58
,
OT_INTERNAL
},
{
"T1"
,
58
,
OT_INTERNAL
},
{
"T2"
,
59
,
OT_INTERNAL
},
{
"T2"
,
59
,
OT_INTERNAL
},
{
"vendor-class"
,
60
,
0
},
{
"vendor-class"
,
60
,
0
},
{
"client-id"
,
61
,
OT_INTERNAL
},
{
"client-id"
,
61
,
OT_INTERNAL
},
{
"nis+-domain"
,
64
,
OT_NAME
},
{
"nis+-domain"
,
64
,
OT_NAME
},
{
"nis+-server"
,
65
,
OT_ADDR_LIST
},
{
"nis+-server"
,
65
,
OT_ADDR_LIST
},
{
"tftp-server"
,
66
,
OT_NAME
},
{
"tftp-server"
,
66
,
OT_NAME
},
...
@@ -447,21 +448,149 @@ static const struct {
...
@@ -447,21 +448,149 @@ static const struct {
{
NULL
,
0
,
0
}
{
NULL
,
0
,
0
}
};
};
char
*
option_string
(
unsigned
char
opt
,
int
*
is_ip
,
int
*
is_name
)
#ifdef HAVE_DHCP6
static
const
struct
opttab_t
opttab6
[]
=
{
{
"client-id"
,
1
,
OT_INTERNAL
},
{
"server-id"
,
2
,
OT_INTERNAL
},
{
"ia-na"
,
3
,
OT_INTERNAL
},
{
"ia-ta"
,
4
,
OT_INTERNAL
},
{
"iaaddr"
,
5
,
OT_INTERNAL
},
{
"oro"
,
6
,
OT_INTERNAL
},
{
"preference"
,
7
,
OT_INTERNAL
},
{
"unicast"
,
12
,
OT_INTERNAL
},
{
"status-code"
,
13
,
OT_INTERNAL
},
{
"rapid-commit"
,
14
,
OT_INTERNAL
},
{
"user-class"
,
15
,
OT_INTERNAL
|
OT_CSTRING
},
{
"vendor-class"
,
16
,
OT_INTERNAL
|
OT_CSTRING
},
{
"vendor-opts"
,
17
,
OT_INTERNAL
},
{
"sip-server-domain"
,
21
,
OT_RFC1035_NAME
},
{
"sip-server"
,
22
,
OT_ADDR_LIST
},
{
"dns-server"
,
23
,
OT_ADDR_LIST
},
{
"domain-search"
,
24
,
OT_RFC1035_NAME
},
{
"nis-server"
,
27
,
OT_ADDR_LIST
},
{
"nis+-server"
,
28
,
OT_ADDR_LIST
},
{
"nis-domain"
,
29
,
OT_RFC1035_NAME
},
{
"nis+-domain"
,
30
,
OT_RFC1035_NAME
},
{
"sntp-server"
,
31
,
OT_ADDR_LIST
},
{
"FQDN"
,
39
,
OT_INTERNAL
|
OT_RFC1035_NAME
},
{
"ntp-server"
,
56
,
OT_ADDR_LIST
},
{
"bootfile-url"
,
59
,
OT_NAME
},
{
"bootfile-param"
,
60
,
OT_CSTRING
},
{
NULL
,
0
,
0
}
};
#endif
char
*
option_string
(
int
prot
,
unsigned
int
opt
,
unsigned
char
*
val
,
int
opt_len
,
char
*
buf
,
int
buf_len
)
{
{
int
i
;
int
o
,
i
,
j
,
nodecode
=
0
;
const
struct
opttab_t
*
ot
=
opttab
;
for
(
i
=
0
;
opttab
[
i
].
name
;
i
++
)
#ifdef HAVE_DHCP6
if
(
opttab
[
i
].
val
==
opt
)
if
(
prot
==
AF_INET6
)
ot
=
opttab6
;
#endif
for
(
o
=
0
;
ot
[
o
].
name
;
o
++
)
if
(
ot
[
o
].
val
==
opt
)
{
{
if
(
is_ip
)
if
(
buf
)
*
is_ip
=
!!
(
opttab
[
i
].
size
&
OT_ADDR_LIST
);
{
if
(
is_name
)
memset
(
buf
,
0
,
buf_len
);
*
is_name
=
!!
(
opttab
[
i
].
size
&
OT_NAME
);
return
opttab
[
i
].
name
;
if
(
ot
[
o
].
size
&
OT_ADDR_LIST
)
{
struct
all_addr
addr
;
int
addr_len
=
INADDRSZ
;
#ifdef HAVE_DHCP6
if
(
prot
==
AF_INET6
)
addr_len
=
IN6ADDRSZ
;
#endif
for
(
buf
[
0
]
=
0
,
i
=
0
;
i
<=
opt_len
-
addr_len
;
i
+=
addr_len
)
{
if
(
i
!=
0
)
strncat
(
buf
,
", "
,
buf_len
-
strlen
(
buf
));
/* align */
memcpy
(
&
addr
,
&
val
[
i
],
addr_len
);
inet_ntop
(
prot
,
&
val
[
i
],
daemon
->
addrbuff
,
ADDRSTRLEN
);
strncat
(
buf
,
daemon
->
addrbuff
,
buf_len
-
strlen
(
buf
));
}
}
else
if
(
ot
[
o
].
size
&
OT_NAME
)
for
(
i
=
0
,
j
=
0
;
i
<
opt_len
&&
j
<
buf_len
;
i
++
)
{
char
c
=
val
[
i
];
if
(
isprint
((
int
)
c
))
buf
[
j
++
]
=
c
;
}
#ifdef HAVE_DHCP6
/* We don't handle compressed rfc1035 names, so no good in IPv4 land */
else
if
((
ot
[
o
].
size
&
OT_RFC1035_NAME
)
&&
prot
==
AF_INET6
)
{
i
=
0
,
j
=
0
;
while
(
i
<
opt_len
&&
val
[
i
]
!=
0
)
{
int
k
,
l
=
i
+
val
[
i
]
+
1
;
for
(
k
=
i
+
1
;
k
<
opt_len
&&
k
<
l
&&
j
<
buf_len
;
k
++
)
{
char
c
=
val
[
k
];
if
(
isprint
((
int
)
c
))
buf
[
j
++
]
=
c
;
}
i
=
l
;
if
(
val
[
i
]
!=
0
&&
j
<
buf_len
)
buf
[
j
++
]
=
'.'
;
}
}
else
if
((
ot
[
o
].
size
&
OT_CSTRING
))
{
int
k
,
len
;
unsigned
char
*
p
;
i
=
0
,
j
=
0
;
while
(
1
)
{
p
=
&
val
[
i
];
GETSHORT
(
len
,
p
);
for
(
k
=
0
;
k
<
len
&&
j
<
buf_len
;
k
++
)
{
char
c
=
*
p
++
;
if
(
isprint
((
int
)
c
))
buf
[
j
++
]
=
c
;
}
i
+=
len
+
2
;
if
(
i
>=
opt_len
)
break
;
if
(
j
<
buf_len
)
buf
[
j
++
]
=
','
;
}
}
#endif
else
nodecode
=
1
;
}
break
;
}
}
return
NULL
;
if
(
buf
&&
(
!
ot
[
o
].
name
||
nodecode
))
{
int
trunc
=
0
;
if
(
opt_len
>
13
)
{
trunc
=
1
;
opt_len
=
13
;
}
print_mac
(
buf
,
val
,
opt_len
);
if
(
trunc
)
strncat
(
buf
,
"..."
,
buf_len
-
strlen
(
buf
));
}
return
ot
[
o
].
name
?
ot
[
o
].
name
:
""
;
}
}
#endif
#endif
...
@@ -699,6 +828,19 @@ static void display_opts(void)
...
@@ -699,6 +828,19 @@ static void display_opts(void)
printf
(
"%3d %s
\n
"
,
opttab
[
i
].
val
,
opttab
[
i
].
name
);
printf
(
"%3d %s
\n
"
,
opttab
[
i
].
val
,
opttab
[
i
].
name
);
}
}
#ifdef HAVE_DHCP6
static
void
display_opts6
(
void
)
{
int
i
;
printf
(
_
(
"Known DHCPv6 options:
\n
"
));
for
(
i
=
0
;
opttab6
[
i
].
name
;
i
++
)
if
(
!
(
opttab6
[
i
].
size
&
OT_INTERNAL
))
printf
(
"%3d %s
\n
"
,
opttab6
[
i
].
val
,
opttab6
[
i
].
name
);
}
#endif
static
int
is_tag_prefix
(
char
*
arg
)
static
int
is_tag_prefix
(
char
*
arg
)
{
{
if
(
arg
&&
(
strstr
(
arg
,
"net:"
)
==
arg
||
strstr
(
arg
,
"tag:"
)
==
arg
))
if
(
arg
&&
(
strstr
(
arg
,
"net:"
)
==
arg
||
strstr
(
arg
,
"tag:"
)
==
arg
))
...
@@ -720,10 +862,11 @@ static char *parse_dhcp_opt(char *arg, int flags)
...
@@ -720,10 +862,11 @@ static char *parse_dhcp_opt(char *arg, int flags)
{
{
struct
dhcp_opt
*
new
=
opt_malloc
(
sizeof
(
struct
dhcp_opt
));
struct
dhcp_opt
*
new
=
opt_malloc
(
sizeof
(
struct
dhcp_opt
));
char
lenchar
=
0
,
*
cp
;
char
lenchar
=
0
,
*
cp
;
int
i
,
addrs
,
digs
,
is_addr
,
is_hex
,
is_dec
,
is_string
,
dots
;
int
i
,
addrs
,
digs
,
is_addr
,
is_
addr6
,
is_
hex
,
is_dec
,
is_string
,
dots
;
char
*
comma
=
NULL
,
*
problem
=
NULL
;
char
*
comma
=
NULL
,
*
problem
=
NULL
;
struct
dhcp_netid
*
np
=
NULL
;
struct
dhcp_netid
*
np
=
NULL
;
unsigned
char
opt_len
=
0
;
u16
opt_len
=
0
;
int
is6
=
0
;
new
->
len
=
0
;
new
->
len
=
0
;
new
->
flags
=
flags
;
new
->
flags
=
flags
;
...
@@ -759,6 +902,32 @@ static char *parse_dhcp_opt(char *arg, int flags)
...
@@ -759,6 +902,32 @@ static char *parse_dhcp_opt(char *arg, int flags)
/* option:<optname> must follow tag and vendor string. */
/* option:<optname> must follow tag and vendor string. */
break
;
break
;
}
}
#ifdef HAVE_DHCP6
else
if
(
strstr
(
arg
,
"option6:"
)
==
arg
)
{
for
(
cp
=
arg
+
8
;
*
cp
;
cp
++
)
if
(
*
cp
<
'0'
||
*
cp
>
'9'
)
break
;
if
(
!*
cp
)
{
new
->
opt
=
atoi
(
arg
+
8
);
opt_len
=
0
;
}
else
for
(
i
=
0
;
opttab6
[
i
].
name
;
i
++
)
if
(
!
(
opttab6
[
i
].
size
&
OT_INTERNAL
)
&&
strcasecmp
(
opttab6
[
i
].
name
,
arg
+
8
)
==
0
)
{
new
->
opt
=
opttab6
[
i
].
val
;
opt_len
=
opttab6
[
i
].
size
;
break
;
}
/* option6:<opt>|<optname> must follow tag and vendor string. */
is6
=
1
;
break
;
}
#endif
else
if
(
strstr
(
arg
,
"vendor:"
)
==
arg
)
else
if
(
strstr
(
arg
,
"vendor:"
)
==
arg
)
{
{
new
->
u
.
vendor_class
=
(
unsigned
char
*
)
opt_string_alloc
(
arg
+
7
);
new
->
u
.
vendor_class
=
(
unsigned
char
*
)
opt_string_alloc
(
arg
+
7
);
...
@@ -793,17 +962,36 @@ static char *parse_dhcp_opt(char *arg, int flags)
...
@@ -793,17 +962,36 @@ static char *parse_dhcp_opt(char *arg, int flags)
arg
=
comma
;
arg
=
comma
;
}
}
if
(
opt_len
==
0
&&
#ifdef HAVE_DHCP6
!
(
new
->
flags
&
(
DHOPT_VENDOR
|
DHOPT_ENCAPSULATE
|
DHOPT_RFC3925
)))
if
(
is6
)
for
(
i
=
0
;
opttab
[
i
].
name
;
i
++
)
{
if
(
new
->
opt
==
opttab
[
i
].
val
)
if
(
new
->
flags
&
(
DHOPT_VENDOR
|
DHOPT_ENCAPSULATE
))
{
problem
=
_
(
"unsupported encapsulation for IPv6 option"
);
opt_len
=
opttab
[
i
].
size
;
if
(
opt_len
&
OT_INTERNAL
)
if
(
opt_len
==
0
&&
opt_len
=
0
;
!
(
new
->
flags
&
DHOPT_RFC3925
))
break
;
for
(
i
=
0
;
opttab6
[
i
].
name
;
i
++
)
}
if
(
new
->
opt
==
opttab6
[
i
].
val
)
{
opt_len
=
opttab6
[
i
].
size
;
if
(
opt_len
&
OT_INTERNAL
)
opt_len
=
0
;
break
;
}
}
else
#endif
if
(
opt_len
==
0
&&
!
(
new
->
flags
&
(
DHOPT_VENDOR
|
DHOPT_ENCAPSULATE
|
DHOPT_RFC3925
)))
for
(
i
=
0
;
opttab
[
i
].
name
;
i
++
)
if
(
new
->
opt
==
opttab
[
i
].
val
)
{
opt_len
=
opttab
[
i
].
size
;
if
(
opt_len
&
OT_INTERNAL
)
opt_len
=
0
;
break
;
}
/* option may be missing with rfc3925 match */
/* option may be missing with rfc3925 match */
if
(
new
->
opt
==
0
)
if
(
new
->
opt
==
0
)
...
@@ -813,7 +1001,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
...
@@ -813,7 +1001,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
/* characterise the value */
/* characterise the value */
char
c
;
char
c
;
int
found_dig
=
0
;
int
found_dig
=
0
;
is_addr
=
is_hex
=
is_dec
=
is_string
=
1
;
is_addr
=
is_
addr6
=
is_
hex
=
is_dec
=
is_string
=
1
;
addrs
=
digs
=
1
;
addrs
=
digs
=
1
;
dots
=
0
;
dots
=
0
;
for
(
cp
=
comma
;
(
c
=
*
cp
);
cp
++
)
for
(
cp
=
comma
;
(
c
=
*
cp
);
cp
++
)
...
@@ -829,17 +1017,17 @@ static char *parse_dhcp_opt(char *arg, int flags)
...
@@ -829,17 +1017,17 @@ static char *parse_dhcp_opt(char *arg, int flags)
}
}
else
if
(
c
==
'/'
)
else
if
(
c
==
'/'
)
{
{
is_dec
=
is_hex
=
0
;
is_
addr6
=
is_
dec
=
is_hex
=
0
;
if
(
cp
==
comma
)
/* leading / means a pathname */
if
(
cp
==
comma
)
/* leading / means a pathname */
is_addr
=
0
;
is_addr
=
0
;
}
}
else
if
(
c
==
'.'
)
else
if
(
c
==
'.'
)
{
{
is_dec
=
is_hex
=
0
;
is_
addr6
=
is_
dec
=
is_hex
=
0
;
dots
++
;
dots
++
;
}
}
else
if
(
c
==
'-'
)
else
if
(
c
==
'-'
)
is_hex
=
is_addr
=
0
;
is_hex
=
is_addr
=
is_addr6
=
0
;
else
if
(
c
==
' '
)
else
if
(
c
==
' '
)
is_dec
=
is_hex
=
0
;
is_dec
=
is_hex
=
0
;
else
if
(
!
(
c
>=
'0'
&&
c
<=
'9'
))
else
if
(
!
(
c
>=
'0'
&&
c
<=
'9'
))
...
@@ -856,25 +1044,33 @@ static char *parse_dhcp_opt(char *arg, int flags)
...
@@ -856,25 +1044,33 @@ static char *parse_dhcp_opt(char *arg, int flags)
if
(
!
((
c
>=
'A'
&&
c
<=
'F'
)
||
if
(
!
((
c
>=
'A'
&&
c
<=
'F'
)
||
(
c
>=
'a'
&&
c
<=
'f'
)
||
(
c
>=
'a'
&&
c
<=
'f'
)
||
(
c
==
'*'
&&
(
flags
&
DHOPT_MATCH
))))
(
c
==
'*'
&&
(
flags
&
DHOPT_MATCH
))))
is_hex
=
0
;
{
is_hex
=
0
;
if
(
c
!=
'['
&&
c
!=
']'
)
is_addr6
=
0
;
}
}
}
else
else
found_dig
=
1
;
found_dig
=
1
;
if
(
!
found_dig
)
if
(
!
found_dig
)
is_dec
=
is_addr
=
0
;
is_dec
=
is_addr
=
0
;
/* We know that some options take addresses */
/* We know that some options take addresses */
if
(
opt_len
&
OT_ADDR_LIST
)
if
(
opt_len
&
OT_ADDR_LIST
)
{
{
is_string
=
is_dec
=
is_hex
=
0
;
is_string
=
is_dec
=
is_hex
=
0
;
if
(
!
is_addr
||
dots
==
0
)
if
(
!
is6
&&
(
!
is_addr
||
dots
==
0
))
problem
=
_
(
"bad IP address"
);
problem
=
_
(
"bad IP address"
);
if
(
is6
&&
!
is_addr6
)
problem
=
_
(
"bad IPv6 address"
);
}
}
/* or names */
/* or names */
else
if
(
opt_len
&
(
OT_NAME
|
OT_RFC1035_NAME
))
else
if
(
opt_len
&
(
OT_NAME
|
OT_RFC1035_NAME
|
OT_CSTRING
))
is_addr
=
is_dec
=
is_hex
=
0
;
is_addr
6
=
is_addr
=
is_dec
=
is_hex
=
0
;
if
(
is_hex
&&
digs
>
1
)
if
(
is_hex
&&
digs
>
1
)
{
{
new
->
len
=
digs
;
new
->
len
=
digs
;
...
@@ -908,7 +1104,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
...
@@ -908,7 +1104,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
for
(
i
=
0
;
i
<
new
->
len
;
i
++
)
for
(
i
=
0
;
i
<
new
->
len
;
i
++
)
new
->
val
[
i
]
=
val
>>
((
new
->
len
-
i
-
1
)
*
8
);
new
->
val
[
i
]
=
val
>>
((
new
->
len
-
i
-
1
)
*
8
);
}
}
else
if
(
is_addr
)
else
if
(
is_addr
&&
!
is6
)
{
{
struct
in_addr
in
;
struct
in_addr
in
;
unsigned
char
*
op
;
unsigned
char
*
op
;
...
@@ -953,11 +1149,37 @@ static char *parse_dhcp_opt(char *arg, int flags)
...
@@ -953,11 +1149,37 @@ static char *parse_dhcp_opt(char *arg, int flags)
}
}
new
->
len
=
op
-
new
->
val
;
new
->
len
=
op
-
new
->
val
;
}
}
else
if
(
is_addr6
&&
is6
)
{
unsigned
char
*
op
;
new
->
val
=
op
=
opt_malloc
(
16
*
addrs
);
new
->
flags
|=
DHOPT_ADDR6
;
while
(
addrs
--
)
{
cp
=
comma
;
comma
=
split
(
cp
);
/* check for [1234::7] */
if
(
*
cp
==
'['
)
cp
++
;
if
(
strlen
(
cp
)
>
1
&&
cp
[
strlen
(
cp
)
-
1
]
==
']'
)
cp
[
strlen
(
cp
)
-
1
]
=
0
;
if
(
inet_pton
(
AF_INET6
,
cp
,
op
))
{
op
+=
IN6ADDRSZ
;
continue
;
}
problem
=
_
(
"bad IPv6 address"
);
}
new
->
len
=
op
-
new
->
val
;
}
else
if
(
is_string
)
else
if
(
is_string
)
{
{
/* text arg */
/* text arg */
if
((
new
->
opt
==
OPTION_DOMAIN_SEARCH
||
new
->
opt
==
OPTION_SIP_SERVER
)
&&
if
((
new
->
opt
==
OPTION_DOMAIN_SEARCH
||
new
->
opt
==
OPTION_SIP_SERVER
)
&&
!
(
new
->
flags
&
(
DHOPT_ENCAPSULATE
|
DHOPT_VENDOR
|
DHOPT_RFC3925
)))
!
is6
&&
!
(
new
->
flags
&
(
DHOPT_ENCAPSULATE
|
DHOPT_VENDOR
|
DHOPT_RFC3925
)))
{
{
/* dns search, RFC 3397, or SIP, RFC 3361 */
/* dns search, RFC 3397, or SIP, RFC 3361 */
unsigned
char
*
q
,
*
r
,
*
tail
;
unsigned
char
*
q
,
*
r
,
*
tail
;
...
@@ -1030,6 +1252,63 @@ static char *parse_dhcp_opt(char *arg, int flags)
...
@@ -1030,6 +1252,63 @@ static char *parse_dhcp_opt(char *arg, int flags)
new
->
len
=
(
int
)
len
+
header_size
;
new
->
len
=
(
int
)
len
+
header_size
;
new
->
val
=
m
;
new
->
val
=
m
;
}
}
#ifdef HAVE_DHCP6
else
if
(
comma
&&
(
opt_len
&
OT_CSTRING
))
{
/* length fields are two bytes so need 16 bits for each string */
int
commas
=
1
;
unsigned
char
*
p
,
*
newp
;
for
(
i
=
0
;
comma
[
i
];
i
++
)
if
(
comma
[
i
]
==
','
)
commas
++
;
newp
=
opt_malloc
(
strlen
(
comma
)
+
(
2
*
commas
));
p
=
newp
;
arg
=
comma
;
comma
=
split
(
arg
);
while
(
arg
&&
*
arg
)
{
u16
len
=
strlen
(
arg
);
PUTSHORT
(
len
,
p
);
memcpy
(
p
,
arg
,
len
);
p
+=
len
;
arg
=
comma
;
comma
=
split
(
arg
);
}
new
->
val
=
newp
;
new
->
len
=
p
-
newp
;
}
else
if
(
comma
&&
(
opt_len
&
OT_RFC1035_NAME
))
{
int
commas
=
1
;
unsigned
char
*
p
,
*
newp
;
for
(
i
=
0
;
comma
[
i
];
i
++
)
if
(
comma
[
i
]
==
','
)
commas
++
;
newp
=
opt_malloc
(
strlen
(
comma
)
+
(
2
*
commas
));
p
=
newp
;
arg
=
comma
;
comma
=
split
(
arg
);
while
(
arg
&&
*
arg
)
{
p
=
do_rfc1035_name
(
p
,
arg
);
*
p
++
=
0
;
arg
=
comma
;
comma
=
split
(
arg
);
}
new
->
val
=
newp
;
new
->
len
=
p
-
newp
;
}
#endif
else
else
{
{
new
->
len
=
strlen
(
comma
);
new
->
len
=
strlen
(
comma
);
...
@@ -1040,9 +1319,10 @@ static char *parse_dhcp_opt(char *arg, int flags)
...
@@ -1040,9 +1319,10 @@ static char *parse_dhcp_opt(char *arg, int flags)
}
}
}
}
if
((
new
->
len
>
255
)
||
if
(
!
is6
&&
((
new
->
len
>
255
)
||
(
new
->
len
>
253
&&
(
new
->
flags
&
(
DHOPT_VENDOR
|
DHOPT_ENCAPSULATE
)))
||
(
new
->
len
>
253
&&
(
new
->
flags
&
(
DHOPT_VENDOR
|
DHOPT_ENCAPSULATE
)))
||
(
new
->
len
>
250
&&
(
new
->
flags
&
DHOPT_RFC3925
)))
(
new
->
len
>
250
&&
(
new
->
flags
&
DHOPT_RFC3925
)
)))
problem
=
_
(
"dhcp-option too long"
);
problem
=
_
(
"dhcp-option too long"
);
if
(
!
problem
)
if
(
!
problem
)
...
@@ -1053,13 +1333,23 @@ static char *parse_dhcp_opt(char *arg, int flags)
...
@@ -1053,13 +1333,23 @@ static char *parse_dhcp_opt(char *arg, int flags)
!
new
->
netid
||
!
new
->
netid
||
new
->
netid
->
next
)
new
->
netid
->
next
)
problem
=
_
(
"illegal dhcp-match"
);
problem
=
_
(
"illegal dhcp-match"
);
else
if
(
is6
)
{
new
->
next
=
daemon
->
dhcp_match6
;
daemon
->
dhcp_match6
=
new
;
}
else
else
{
{
new
->
next
=
daemon
->
dhcp_match
;
new
->
next
=
daemon
->
dhcp_match
;
daemon
->
dhcp_match
=
new
;
daemon
->
dhcp_match
=
new
;
}
}
}
}
else
else
if
(
is6
)
{
new
->
next
=
daemon
->
dhcp_opts6
;
daemon
->
dhcp_opts6
=
new
;
}
else
{
{
new
->
next
=
daemon
->
dhcp_opts
;
new
->
next
=
daemon
->
dhcp_opts
;
daemon
->
dhcp_opts
=
new
;
daemon
->
dhcp_opts
=
new
;
...
@@ -1367,14 +1657,15 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
...
@@ -1367,14 +1657,15 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
unhide_metas
(
comma
);
unhide_metas
(
comma
);
if
((
netpart
=
split_chr
(
comma
,
'/'
)))
if
((
netpart
=
split_chr
(
comma
,
'/'
)))
{
{
int
msize
,
mask
;
int
msize
;
arg
=
split
(
netpart
);
arg
=
split
(
netpart
);
if
((
new
->
start
.
s_addr
=
inet_addr
(
comma
))
==
(
in_addr_t
)
-
1
||
if
(
!
atoi_check
(
netpart
,
&
msize
))
!
atoi_check
(
netpart
,
&
msize
))
option
=
'?'
;
option
=
'?'
;
else
else
if
(
inet_pton
(
AF_INET
,
comma
,
&
new
->
start
))
{
{
mask
=
(
1
<<
(
32
-
msize
))
-
1
;
int
mask
=
(
1
<<
(
32
-
msize
))
-
1
;
new
->
is6
=
0
;
new
->
start
.
s_addr
=
ntohl
(
htonl
(
new
->
start
.
s_addr
)
&
~
mask
);
new
->
start
.
s_addr
=
ntohl
(
htonl
(
new
->
start
.
s_addr
)
&
~
mask
);
new
->
end
.
s_addr
=
new
->
start
.
s_addr
|
htonl
(
mask
);
new
->
end
.
s_addr
=
new
->
start
.
s_addr
|
htonl
(
mask
);
if
(
arg
)
if
(
arg
)
...
@@ -1416,19 +1707,92 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
...
@@ -1416,19 +1707,92 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
}
}
}
}
}
}
#ifdef HAVE_IPV6
else
if
(
inet_pton
(
AF_INET6
,
comma
,
&
new
->
start6
))
{
u64
mask
=
(
1LLU
<<
(
128
-
msize
))
-
1LLU
;
u64
addrpart
=
addr6part
(
&
new
->
start6
);
new
->
is6
=
1
;
/* prefix==64 overflows the mask calculation above */
if
(
msize
==
64
)
mask
=
(
u64
)
-
1LL
;
new
->
end6
=
new
->
start6
;
setaddr6part
(
&
new
->
start6
,
addrpart
&
~
mask
);
setaddr6part
(
&
new
->
end6
,
addrpart
|
mask
);
if
(
msize
<
64
)
option
=
'?'
;
else
if
(
arg
)
{
/* generate the equivalent of
local=/<domain>/
local=/xxx.yyy.zzz.ip6.arpa/ */
if
(
strcmp
(
arg
,
"local"
)
!=
0
||
((
msize
&
4
)
!=
0
))
option
=
'?'
;
else
{
struct
server
*
serv
=
opt_malloc
(
sizeof
(
struct
server
));
char
*
p
;
memset
(
serv
,
0
,
sizeof
(
struct
server
));
serv
->
domain
=
d
;
serv
->
flags
=
SERV_HAS_DOMAIN
|
SERV_NO_ADDR
;
serv
->
next
=
daemon
->
servers
;
daemon
->
servers
=
serv
;
serv
=
opt_malloc
(
sizeof
(
struct
server
));
memset
(
serv
,
0
,
sizeof
(
struct
server
));
p
=
serv
->
domain
=
opt_malloc
(
73
);
/* strlen("32*<n.>ip6.arpa")+1 */
for
(
i
=
msize
-
1
;
i
>=
0
;
i
-=
4
)
{
int
dig
=
((
unsigned
char
*
)
&
new
->
start6
)[
i
>>
3
];
p
+=
sprintf
(
p
,
"%.1x."
,
(
i
>>
2
)
&
1
?
dig
&
15
:
dig
>>
4
);
}
p
+=
sprintf
(
p
,
"ip6.arpa"
);
serv
->
flags
=
SERV_HAS_DOMAIN
|
SERV_NO_ADDR
;
serv
->
next
=
daemon
->
servers
;
daemon
->
servers
=
serv
;
}
}
}
#endif
else
option
=
'?'
;
}
}
else
if
((
arg
=
split
(
comma
)))
else
{
{
if
((
new
->
start
.
s_addr
=
inet_addr
(
comma
))
==
(
in_addr_t
)
-
1
||
arg
=
split
(
comma
);
(
new
->
end
.
s_addr
=
inet_addr
(
arg
))
==
(
in_addr_t
)
-
1
)
if
(
inet_pton
(
AF_INET
,
comma
,
&
new
->
start
))
{
new
->
is6
=
0
;
if
(
!
arg
)
new
->
end
.
s_addr
=
new
->
start
.
s_addr
;
else
if
(
!
inet_pton
(
AF_INET
,
arg
,
&
new
->
end
))
option
=
'?'
;
}
#ifdef HAVE_IPV6
else
if
(
inet_pton
(
AF_INET6
,
comma
,
&
new
->
start6
))
{
new
->
is6
=
1
;
if
(
!
arg
)
memcpy
(
&
new
->
end6
,
&
new
->
start6
,
IN6ADDRSZ
);
else
if
(
!
inet_pton
(
AF_INET6
,
arg
,
&
new
->
end6
))
option
=
'?'
;
}
#endif
else
option
=
'?'
;
option
=
'?'
;
}
else
if
((
new
->
start
.
s_addr
=
new
->
end
.
s_addr
=
inet_addr
(
comma
))
==
(
in_addr_t
)
-
1
)
option
=
'?'
;
new
->
domain
=
d
;
new
->
domain
=
d
;
new
->
next
=
daemon
->
cond_domain
;
new
->
next
=
daemon
->
cond_domain
;
daemon
->
cond_domain
=
new
;
daemon
->
cond_domain
=
new
;
}
}
}
else
else
daemon
->
domain_suffix
=
d
;
daemon
->
domain_suffix
=
d
;
...
@@ -1989,6 +2353,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
...
@@ -1989,6 +2353,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
{
{
new
->
prefix
=
pref
;
new
->
prefix
=
pref
;
leasepos
=
3
;
leasepos
=
3
;
if
(
new
->
prefix
<
64
)
problem
=
_
(
"prefix must be at least 64"
);
}
}
}
}
if
(
!
is_same_net6
(
&
new
->
start6
,
&
new
->
end6
,
new
->
prefix
))
if
(
!
is_same_net6
(
&
new
->
start6
,
&
new
->
end6
,
new
->
prefix
))
...
@@ -2109,6 +2475,18 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
...
@@ -2109,6 +2475,18 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
}
}
else
if
(
strstr
(
arg
,
"tag:"
)
==
arg
)
else
if
(
strstr
(
arg
,
"tag:"
)
==
arg
)
problem
=
_
(
"cannot match tags in --dhcp-host"
);
problem
=
_
(
"cannot match tags in --dhcp-host"
);
#ifdef HAVE_DHCP6
else
if
(
arg
[
0
]
==
'['
&&
arg
[
strlen
(
arg
)
-
1
]
==
']'
)
{
arg
[
strlen
(
arg
)
-
1
]
=
0
;
arg
++
;
if
(
!
inet_pton
(
AF_INET6
,
arg
,
&
new
->
addr6
))
problem
=
_
(
"bad IPv6 address"
);
new
->
flags
|=
CONFIG_ADDR6
;
}
#endif
else
else
{
{
struct
hwaddr_config
*
newhw
=
opt_malloc
(
sizeof
(
struct
hwaddr_config
));
struct
hwaddr_config
*
newhw
=
opt_malloc
(
sizeof
(
struct
hwaddr_config
));
...
@@ -2500,6 +2878,18 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
...
@@ -2500,6 +2878,18 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
new
->
netid
.
net
=
opt_string_alloc
(
set_prefix
(
arg
));
new
->
netid
.
net
=
opt_string_alloc
(
set_prefix
(
arg
));
/* check for hex string - must digits may include : must not have nothing else,
/* check for hex string - must digits may include : must not have nothing else,
only allowed for agent-options. */
only allowed for agent-options. */
arg
=
comma
;
if
((
comma
=
split
(
arg
)))
{
if
(
option
!=
'U'
||
strstr
(
arg
,
"enterprise:"
)
!=
arg
)
option
=
'?'
;
else
new
->
enterprise
=
atoi
(
arg
+
11
);
}
else
comma
=
arg
;
for
(
p
=
(
unsigned
char
*
)
comma
;
*
p
;
p
++
)
for
(
p
=
(
unsigned
char
*
)
comma
;
*
p
;
p
++
)
if
(
isxdigit
(
*
p
))
if
(
isxdigit
(
*
p
))
dig
=
1
;
dig
=
1
;
...
@@ -3346,12 +3736,17 @@ void read_opts(int argc, char **argv, char *compile_opts)
...
@@ -3346,12 +3736,17 @@ void read_opts(int argc, char **argv, char *compile_opts)
testmode
=
1
;
testmode
=
1
;
else
if
(
option
==
'w'
)
else
if
(
option
==
'w'
)
{
{
if
(
argc
!=
3
||
strcmp
(
argv
[
2
],
"dhcp"
)
!=
0
)
do_usage
();
#ifdef HAVE_DHCP
#ifdef HAVE_DHCP
else
if
(
argc
==
3
&&
strcmp
(
argv
[
2
],
"dhcp"
)
==
0
)
display_opts
();
display_opts
();
#ifdef HAVE_DHCP6
else
if
(
argc
==
3
&&
strcmp
(
argv
[
2
],
"dhcp6"
)
==
0
)
display_opts6
();
#endif
else
#endif
#endif
do_usage
();
exit
(
0
);
exit
(
0
);
}
}
else
if
(
option
==
'v'
)
else
if
(
option
==
'v'
)
...
...
src/rfc2131.c
View file @
c6cc03ed
...
@@ -18,16 +18,13 @@
...
@@ -18,16 +18,13 @@
#ifdef HAVE_DHCP
#ifdef HAVE_DHCP
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
#ifdef HAVE_SCRIPT
#ifdef HAVE_SCRIPT
static
void
add_extradata_data
(
struct
dhcp_lease
*
lease
,
unsigned
char
*
data
,
size_t
len
,
int
delim
);
static
void
add_extradata_opt
(
struct
dhcp_lease
*
lease
,
unsigned
char
*
opt
);
static
void
add_extradata_opt
(
struct
dhcp_lease
*
lease
,
unsigned
char
*
opt
);
#endif
#endif
static
int
match_bytes
(
struct
dhcp_opt
*
o
,
unsigned
char
*
p
,
int
len
);
static
int
sanitise
(
unsigned
char
*
opt
,
char
*
buf
);
static
int
sanitise
(
unsigned
char
*
opt
,
char
*
buf
);
static
struct
in_addr
server_id
(
struct
dhcp_context
*
context
,
struct
in_addr
override
,
struct
in_addr
fallback
);
static
struct
in_addr
server_id
(
struct
dhcp_context
*
context
,
struct
in_addr
override
,
struct
in_addr
fallback
);
static
unsigned
int
calc_time
(
struct
dhcp_context
*
context
,
struct
dhcp_config
*
config
,
unsigned
char
*
opt
);
static
unsigned
int
calc_time
(
struct
dhcp_context
*
context
,
struct
dhcp_config
*
config
,
unsigned
char
*
opt
);
...
@@ -35,13 +32,11 @@ static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, in
...
@@ -35,13 +32,11 @@ static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, in
static
void
option_put_string
(
struct
dhcp_packet
*
mess
,
unsigned
char
*
end
,
static
void
option_put_string
(
struct
dhcp_packet
*
mess
,
unsigned
char
*
end
,
int
opt
,
char
*
string
,
int
null_term
);
int
opt
,
char
*
string
,
int
null_term
);
static
struct
in_addr
option_addr
(
unsigned
char
*
opt
);
static
struct
in_addr
option_addr
(
unsigned
char
*
opt
);
static
struct
in_addr
option_addr_arr
(
unsigned
char
*
opt
,
int
offset
);
static
unsigned
int
option_uint
(
unsigned
char
*
opt
,
int
i
,
int
size
);
static
unsigned
int
option_uint
(
unsigned
char
*
opt
,
int
i
,
int
size
);
static
void
log_packet
(
char
*
type
,
void
*
addr
,
unsigned
char
*
ext_mac
,
static
void
log_packet
(
char
*
type
,
void
*
addr
,
unsigned
char
*
ext_mac
,
int
mac_len
,
char
*
interface
,
char
*
string
,
u32
xid
);
int
mac_len
,
char
*
interface
,
char
*
string
,
u32
xid
);
static
unsigned
char
*
option_find
(
struct
dhcp_packet
*
mess
,
size_t
size
,
int
opt_type
,
int
minsize
);
static
unsigned
char
*
option_find
(
struct
dhcp_packet
*
mess
,
size_t
size
,
int
opt_type
,
int
minsize
);
static
unsigned
char
*
option_find1
(
unsigned
char
*
p
,
unsigned
char
*
end
,
int
opt
,
int
minsize
);
static
unsigned
char
*
option_find1
(
unsigned
char
*
p
,
unsigned
char
*
end
,
int
opt
,
int
minsize
);
static
void
log_tags
(
struct
dhcp_netid
*
netid
,
struct
dhcp_packet
*
mess
);
static
size_t
dhcp_packet_size
(
struct
dhcp_packet
*
mess
,
unsigned
char
*
agent_id
,
unsigned
char
*
real_end
);
static
size_t
dhcp_packet_size
(
struct
dhcp_packet
*
mess
,
unsigned
char
*
agent_id
,
unsigned
char
*
real_end
);
static
void
clear_packet
(
struct
dhcp_packet
*
mess
,
unsigned
char
*
end
);
static
void
clear_packet
(
struct
dhcp_packet
*
mess
,
unsigned
char
*
end
);
static
void
do_options
(
struct
dhcp_context
*
context
,
static
void
do_options
(
struct
dhcp_context
*
context
,
...
@@ -49,7 +44,7 @@ static void do_options(struct dhcp_context *context,
...
@@ -49,7 +44,7 @@ static void do_options(struct dhcp_context *context,
unsigned
char
*
real_end
,
unsigned
char
*
real_end
,
unsigned
char
*
req_options
,
unsigned
char
*
req_options
,
char
*
hostname
,
char
*
hostname
,
char
*
domain
,
char
*
config_domain
,
char
*
config_domain
,
struct
dhcp_netid
*
netid
,
struct
dhcp_netid
*
netid
,
struct
in_addr
subnet_addr
,
struct
in_addr
subnet_addr
,
unsigned
char
fqdn_flags
,
unsigned
char
fqdn_flags
,
...
@@ -468,7 +463,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -468,7 +463,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
tagif_netid
=
run_tag_if
(
&
context
->
netid
);
tagif_netid
=
run_tag_if
(
&
context
->
netid
);
}
}
log_tags
(
tagif_netid
,
mess
);
log_tags
(
tagif_netid
,
ntohl
(
mess
->
xid
)
);
if
(
!
message
&&
!
nailed
)
if
(
!
message
&&
!
nailed
)
{
{
...
@@ -490,7 +485,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -490,7 +485,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_set_hwaddr
(
lease
,
mess
->
chaddr
,
NULL
,
mess
->
hlen
,
mess
->
htype
,
0
);
lease_set_hwaddr
(
lease
,
mess
->
chaddr
,
NULL
,
mess
->
hlen
,
mess
->
htype
,
0
);
if
(
hostname
)
if
(
hostname
)
lease_set_hostname
(
lease
,
hostname
,
1
);
lease_set_hostname
(
lease
,
hostname
,
1
,
get_domain
(
lease
->
addr
),
domain
);
/* infinite lease unless nailed in dhcp-host line. */
/* infinite lease unless nailed in dhcp-host line. */
lease_set_expires
(
lease
,
lease_set_expires
(
lease
,
have_config
(
config
,
CONFIG_TIME
)
?
config
->
lease_time
:
0xffffffff
,
have_config
(
config
,
CONFIG_TIME
)
?
config
->
lease_time
:
0xffffffff
,
...
@@ -499,7 +494,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -499,7 +494,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clear_packet
(
mess
,
end
);
clear_packet
(
mess
,
end
);
do_options
(
context
,
mess
,
end
,
NULL
,
hostname
,
get_domain
(
mess
->
yiaddr
),
do_options
(
context
,
mess
,
end
,
NULL
,
hostname
,
get_domain
(
mess
->
yiaddr
),
domain
,
netid
,
subnet_addr
,
0
,
0
,
0
,
NULL
,
0
,
now
);
netid
,
subnet_addr
,
0
,
0
,
0
,
NULL
,
0
,
now
);
}
}
}
}
...
@@ -821,7 +816,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -821,7 +816,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
do_encap_opts
(
&
opt71
,
OPTION_VENDOR_CLASS_OPT
,
DHOPT_VENDOR_MATCH
,
mess
,
end
,
0
);
do_encap_opts
(
&
opt71
,
OPTION_VENDOR_CLASS_OPT
,
DHOPT_VENDOR_MATCH
,
mess
,
end
,
0
);
log_packet
(
"PXE"
,
&
mess
->
yiaddr
,
emac
,
emac_len
,
iface_name
,
(
char
*
)
mess
->
file
,
mess
->
xid
);
log_packet
(
"PXE"
,
&
mess
->
yiaddr
,
emac
,
emac_len
,
iface_name
,
(
char
*
)
mess
->
file
,
mess
->
xid
);
log_tags
(
tagif_netid
,
mess
);
log_tags
(
tagif_netid
,
ntohl
(
mess
->
xid
)
);
return
dhcp_packet_size
(
mess
,
agent_id
,
real_end
);
return
dhcp_packet_size
(
mess
,
agent_id
,
real_end
);
}
}
...
@@ -873,7 +868,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -873,7 +868,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
do_encap_opts
(
pxe_opts
(
pxearch
,
tagif_netid
,
context
->
local
,
now
),
OPTION_VENDOR_CLASS_OPT
,
DHOPT_VENDOR_MATCH
,
mess
,
end
,
0
);
do_encap_opts
(
pxe_opts
(
pxearch
,
tagif_netid
,
context
->
local
,
now
),
OPTION_VENDOR_CLASS_OPT
,
DHOPT_VENDOR_MATCH
,
mess
,
end
,
0
);
log_packet
(
"PXE"
,
NULL
,
emac
,
emac_len
,
iface_name
,
ignore
?
"proxy-ignored"
:
"proxy"
,
mess
->
xid
);
log_packet
(
"PXE"
,
NULL
,
emac
,
emac_len
,
iface_name
,
ignore
?
"proxy-ignored"
:
"proxy"
,
mess
->
xid
);
log_tags
(
tagif_netid
,
mess
);
log_tags
(
tagif_netid
,
ntohl
(
mess
->
xid
)
);
return
ignore
?
0
:
dhcp_packet_size
(
mess
,
agent_id
,
real_end
);
return
ignore
?
0
:
dhcp_packet_size
(
mess
,
agent_id
,
real_end
);
}
}
}
}
...
@@ -1011,7 +1006,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -1011,7 +1006,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
tagif_netid
=
run_tag_if
(
&
context
->
netid
);
tagif_netid
=
run_tag_if
(
&
context
->
netid
);
}
}
log_tags
(
tagif_netid
,
mess
);
log_tags
(
tagif_netid
,
ntohl
(
mess
->
xid
)
);
log_packet
(
"DHCPOFFER"
,
&
mess
->
yiaddr
,
emac
,
emac_len
,
iface_name
,
NULL
,
mess
->
xid
);
log_packet
(
"DHCPOFFER"
,
&
mess
->
yiaddr
,
emac
,
emac_len
,
iface_name
,
NULL
,
mess
->
xid
);
...
@@ -1027,7 +1022,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -1027,7 +1022,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put
(
mess
,
end
,
OPTION_T2
,
4
,
(
time
*
7
)
/
8
);
option_put
(
mess
,
end
,
OPTION_T2
,
4
,
(
time
*
7
)
/
8
);
}
}
do_options
(
context
,
mess
,
end
,
req_options
,
offer_hostname
,
get_domain
(
mess
->
yiaddr
),
do_options
(
context
,
mess
,
end
,
req_options
,
offer_hostname
,
get_domain
(
mess
->
yiaddr
),
domain
,
netid
,
subnet_addr
,
fqdn_flags
,
borken_opt
,
pxearch
,
uuid
,
vendor_class_len
,
now
);
netid
,
subnet_addr
,
fqdn_flags
,
borken_opt
,
pxearch
,
uuid
,
vendor_class_len
,
now
);
return
dhcp_packet_size
(
mess
,
agent_id
,
real_end
);
return
dhcp_packet_size
(
mess
,
agent_id
,
real_end
);
...
@@ -1225,7 +1220,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -1225,7 +1220,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
tagif_netid
=
run_tag_if
(
&
context
->
netid
);
tagif_netid
=
run_tag_if
(
&
context
->
netid
);
}
}
log_tags
(
tagif_netid
,
mess
);
log_tags
(
tagif_netid
,
ntohl
(
mess
->
xid
)
);
#ifdef HAVE_SCRIPT
#ifdef HAVE_SCRIPT
if
(
do_classes
&&
daemon
->
lease_change_command
)
if
(
do_classes
&&
daemon
->
lease_change_command
)
...
@@ -1235,7 +1230,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -1235,7 +1230,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if
(
mess
->
giaddr
.
s_addr
)
if
(
mess
->
giaddr
.
s_addr
)
lease
->
giaddr
=
mess
->
giaddr
;
lease
->
giaddr
=
mess
->
giaddr
;
lease
->
changed
=
1
;
lease
->
flags
|=
LEASE_CHANGED
;
free
(
lease
->
extradata
);
free
(
lease
->
extradata
);
lease
->
extradata
=
NULL
;
lease
->
extradata
=
NULL
;
lease
->
extradata_size
=
lease
->
extradata_len
=
0
;
lease
->
extradata_size
=
lease
->
extradata_len
=
0
;
...
@@ -1258,7 +1253,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -1258,7 +1253,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if
(
strcmp
(
n
->
net
,
n1
->
net
)
==
0
)
if
(
strcmp
(
n
->
net
,
n1
->
net
)
==
0
)
break
;
break
;
if
(
!
n1
)
if
(
!
n1
)
add_extradata_
data
(
lease
,
(
unsigned
char
*
)
n
->
net
,
strlen
(
n
->
net
),
n
->
next
?
' '
:
0
);
lease_add_extra
data
(
lease
,
(
unsigned
char
*
)
n
->
net
,
strlen
(
n
->
net
),
n
->
next
?
' '
:
0
);
}
}
if
((
opt
=
option_find
(
mess
,
sz
,
OPTION_USER_CLASS
,
1
)))
if
((
opt
=
option_find
(
mess
,
sz
,
OPTION_USER_CLASS
,
1
)))
...
@@ -1268,7 +1263,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -1268,7 +1263,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
/* If the user-class option started as counted strings, the first byte will be zero. */
/* If the user-class option started as counted strings, the first byte will be zero. */
if
(
len
!=
0
&&
ucp
[
0
]
==
0
)
if
(
len
!=
0
&&
ucp
[
0
]
==
0
)
ucp
++
,
len
--
;
ucp
++
,
len
--
;
add_extradata_
data
(
lease
,
ucp
,
len
,
0
);
lease_add_extra
data
(
lease
,
ucp
,
len
,
0
);
}
}
}
}
#endif
#endif
...
@@ -1312,7 +1307,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -1312,7 +1307,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
}
if
(
hostname
)
if
(
hostname
)
lease_set_hostname
(
lease
,
hostname
,
hostname_auth
);
lease_set_hostname
(
lease
,
hostname
,
hostname_auth
,
get_domain
(
lease
->
addr
),
domain
);
lease_set_expires
(
lease
,
time
,
now
);
lease_set_expires
(
lease
,
time
,
now
);
lease_set_interface
(
lease
,
int_index
);
lease_set_interface
(
lease
,
int_index
);
...
@@ -1336,7 +1331,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -1336,7 +1331,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put
(
mess
,
end
,
OPTION_T2
,
4
,
((
time
/
8
)
*
7
)
-
fuzz
);
option_put
(
mess
,
end
,
OPTION_T2
,
4
,
((
time
/
8
)
*
7
)
-
fuzz
);
}
}
do_options
(
context
,
mess
,
end
,
req_options
,
hostname
,
get_domain
(
mess
->
yiaddr
),
do_options
(
context
,
mess
,
end
,
req_options
,
hostname
,
get_domain
(
mess
->
yiaddr
),
domain
,
netid
,
subnet_addr
,
fqdn_flags
,
borken_opt
,
pxearch
,
uuid
,
vendor_class_len
,
now
);
netid
,
subnet_addr
,
fqdn_flags
,
borken_opt
,
pxearch
,
uuid
,
vendor_class_len
,
now
);
}
}
return
dhcp_packet_size
(
mess
,
agent_id
,
real_end
);
return
dhcp_packet_size
(
mess
,
agent_id
,
real_end
);
...
@@ -1366,10 +1361,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -1366,10 +1361,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if
(
context
&&
context
->
netid
.
net
)
if
(
context
&&
context
->
netid
.
net
)
{
{
context
->
netid
.
next
=
netid
;
context
->
netid
.
next
=
netid
;
tagif_netid
=
run_tag_if
(
&
context
->
netid
);
tagif_netid
=
run_tag_if
(
&
context
->
netid
);
}
}
log_tags
(
tagif_netid
,
mess
);
log_tags
(
tagif_netid
,
ntohl
(
mess
->
xid
)
);
log_packet
(
"DHCPACK"
,
&
mess
->
ciaddr
,
emac
,
emac_len
,
iface_name
,
hostname
,
mess
->
xid
);
log_packet
(
"DHCPACK"
,
&
mess
->
ciaddr
,
emac
,
emac_len
,
iface_name
,
hostname
,
mess
->
xid
);
...
@@ -1396,7 +1391,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -1396,7 +1391,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
}
do_options
(
context
,
mess
,
end
,
req_options
,
hostname
,
get_domain
(
mess
->
ciaddr
),
do_options
(
context
,
mess
,
end
,
req_options
,
hostname
,
get_domain
(
mess
->
ciaddr
),
domain
,
netid
,
subnet_addr
,
fqdn_flags
,
borken_opt
,
pxearch
,
uuid
,
vendor_class_len
,
now
);
netid
,
subnet_addr
,
fqdn_flags
,
borken_opt
,
pxearch
,
uuid
,
vendor_class_len
,
now
);
*
is_inform
=
1
;
/* handle reply differently */
*
is_inform
=
1
;
/* handle reply differently */
return
dhcp_packet_size
(
mess
,
agent_id
,
real_end
);
return
dhcp_packet_size
(
mess
,
agent_id
,
real_end
);
...
@@ -1405,37 +1400,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
...
@@ -1405,37 +1400,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
return
0
;
return
0
;
}
}
static
int
match_bytes
(
struct
dhcp_opt
*
o
,
unsigned
char
*
p
,
int
len
)
{
int
i
;
if
(
o
->
len
>
len
)
return
0
;
if
(
o
->
len
==
0
)
return
1
;
if
(
o
->
flags
&
DHOPT_HEX
)
{
if
(
memcmp_masked
(
o
->
val
,
p
,
o
->
len
,
o
->
u
.
wildcard_mask
))
return
1
;
}
else
for
(
i
=
0
;
i
<=
(
len
-
o
->
len
);
)
{
if
(
memcmp
(
o
->
val
,
p
+
i
,
o
->
len
)
==
0
)
return
1
;
if
(
o
->
flags
&
DHOPT_STRING
)
i
++
;
else
i
+=
o
->
len
;
}
return
0
;
}
/* find a good value to use as MAC address for logging and address-allocation hashing.
/* find a good value to use as MAC address for logging and address-allocation hashing.
This is normally just the chaddr field from the DHCP packet,
This is normally just the chaddr field from the DHCP packet,
but eg Firewire will have hlen == 0 and use the client-id instead.
but eg Firewire will have hlen == 0 and use the client-id instead.
...
@@ -1521,51 +1485,12 @@ static int sanitise(unsigned char *opt, char *buf)
...
@@ -1521,51 +1485,12 @@ static int sanitise(unsigned char *opt, char *buf)
}
}
#ifdef HAVE_SCRIPT
#ifdef HAVE_SCRIPT
static
void
add_extradata_data
(
struct
dhcp_lease
*
lease
,
unsigned
char
*
data
,
size_t
len
,
int
delim
)
{
if
((
lease
->
extradata_size
-
lease
->
extradata_len
)
<
(
len
+
1
))
{
size_t
newsz
=
lease
->
extradata_len
+
len
+
100
;
unsigned
char
*
new
=
whine_malloc
(
newsz
);
if
(
!
new
)
return
;
if
(
lease
->
extradata
)
{
memcpy
(
new
,
lease
->
extradata
,
lease
->
extradata_len
);
free
(
lease
->
extradata
);
}
lease
->
extradata
=
new
;
lease
->
extradata_size
=
newsz
;
}
if
(
len
!=
0
)
memcpy
(
lease
->
extradata
+
lease
->
extradata_len
,
data
,
len
);
lease
->
extradata
[
lease
->
extradata_len
+
len
]
=
delim
;
lease
->
extradata_len
+=
len
+
1
;
}
static
void
add_extradata_opt
(
struct
dhcp_lease
*
lease
,
unsigned
char
*
opt
)
static
void
add_extradata_opt
(
struct
dhcp_lease
*
lease
,
unsigned
char
*
opt
)
{
{
if
(
!
opt
)
if
(
!
opt
)
add_extradata_
data
(
lease
,
NULL
,
0
,
0
);
lease_add_extra
data
(
lease
,
NULL
,
0
,
0
);
else
else
{
lease_add_extradata
(
lease
,
option_ptr
(
opt
,
0
),
option_len
(
opt
),
0
);
size_t
i
,
len
=
option_len
(
opt
);
unsigned
char
*
ucp
=
option_ptr
(
opt
,
0
);
/* check for embeded NULLs */
for
(
i
=
0
;
i
<
len
;
i
++
)
if
(
ucp
[
i
]
==
0
)
{
len
=
i
;
break
;
}
add_extradata_data
(
lease
,
ucp
,
len
,
0
);
}
}
}
#endif
#endif
...
@@ -1603,30 +1528,10 @@ static void log_options(unsigned char *start, u32 xid)
...
@@ -1603,30 +1528,10 @@ static void log_options(unsigned char *start, u32 xid)
{
{
while
(
*
start
!=
OPTION_END
)
while
(
*
start
!=
OPTION_END
)
{
{
int
is_ip
,
is_name
,
i
;
char
*
optname
=
option_string
(
AF_INET
,
start
[
0
],
option_ptr
(
start
,
0
),
option_len
(
start
),
daemon
->
namebuff
,
MAXDNAME
);
char
*
text
=
option_string
(
start
[
0
],
&
is_ip
,
&
is_name
);
unsigned
char
trunc
=
option_len
(
start
);
if
(
is_ip
)
my_syslog
(
MS_DHCP
|
LOG_INFO
,
"%u sent size:%3d option:%3d %s %s"
,
for
(
daemon
->
namebuff
[
0
]
=
0
,
i
=
0
;
i
<=
trunc
-
INADDRSZ
;
i
+=
INADDRSZ
)
ntohl
(
xid
),
option_len
(
start
),
start
[
0
],
optname
,
daemon
->
namebuff
);
{
if
(
i
!=
0
)
strncat
(
daemon
->
namebuff
,
", "
,
256
-
strlen
(
daemon
->
namebuff
));
strncat
(
daemon
->
namebuff
,
inet_ntoa
(
option_addr_arr
(
start
,
i
)),
256
-
strlen
(
daemon
->
namebuff
));
}
else
if
(
!
is_name
||
!
sanitise
(
start
,
daemon
->
namebuff
))
{
if
(
trunc
>
13
)
trunc
=
13
;
print_mac
(
daemon
->
namebuff
,
option_ptr
(
start
,
0
),
trunc
);
}
my_syslog
(
MS_DHCP
|
LOG_INFO
,
"%u sent size:%3d option:%3d%s%s%s%s%s"
,
ntohl
(
xid
),
option_len
(
start
),
start
[
0
],
text
?
":"
:
""
,
text
?
text
:
""
,
trunc
==
0
?
""
:
" "
,
trunc
==
0
?
""
:
daemon
->
namebuff
,
trunc
==
option_len
(
start
)
?
""
:
"..."
);
start
+=
start
[
1
]
+
2
;
start
+=
start
[
1
]
+
2
;
}
}
}
}
...
@@ -1681,22 +1586,17 @@ static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt
...
@@ -1681,22 +1586,17 @@ static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt
return
NULL
;
return
NULL
;
}
}
static
struct
in_addr
option_addr
_arr
(
unsigned
char
*
opt
,
int
offse
t
)
static
struct
in_addr
option_addr
(
unsigned
char
*
op
t
)
{
{
/* this worries about unaligned data in the option. */
/* this worries about unaligned data in the option. */
/* struct in_addr is network byte order */
/* struct in_addr is network byte order */
struct
in_addr
ret
;
struct
in_addr
ret
;
memcpy
(
&
ret
,
option_ptr
(
opt
,
offset
),
INADDRSZ
);
memcpy
(
&
ret
,
option_ptr
(
opt
,
0
),
INADDRSZ
);
return
ret
;
return
ret
;
}
}
static
struct
in_addr
option_addr
(
unsigned
char
*
opt
)
{
return
option_addr_arr
(
opt
,
0
);
}
static
unsigned
int
option_uint
(
unsigned
char
*
opt
,
int
offset
,
int
size
)
static
unsigned
int
option_uint
(
unsigned
char
*
opt
,
int
offset
,
int
size
)
{
{
/* this worries about unaligned data and byte order */
/* this worries about unaligned data and byte order */
...
@@ -1731,31 +1631,6 @@ static unsigned char *find_overload(struct dhcp_packet *mess)
...
@@ -1731,31 +1631,6 @@ static unsigned char *find_overload(struct dhcp_packet *mess)
return
NULL
;
return
NULL
;
}
}
static
void
log_tags
(
struct
dhcp_netid
*
netid
,
struct
dhcp_packet
*
mess
)
{
if
(
netid
&&
option_bool
(
OPT_LOG_OPTS
))
{
char
*
s
=
daemon
->
namebuff
;
for
(
*
s
=
0
;
netid
;
netid
=
netid
->
next
)
{
/* kill dupes. */
struct
dhcp_netid
*
n
;
for
(
n
=
netid
->
next
;
n
;
n
=
n
->
next
)
if
(
strcmp
(
netid
->
net
,
n
->
net
)
==
0
)
break
;
if
(
!
n
)
{
strncat
(
s
,
netid
->
net
,
(
MAXDNAME
-
1
)
-
strlen
(
s
));
if
(
netid
->
next
)
strncat
(
s
,
", "
,
(
MAXDNAME
-
1
)
-
strlen
(
s
));
}
}
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"%u tags: %s"
),
ntohl
(
mess
->
xid
),
s
);
}
}
static
size_t
dhcp_packet_size
(
struct
dhcp_packet
*
mess
,
unsigned
char
*
agent_id
,
unsigned
char
*
real_end
)
static
size_t
dhcp_packet_size
(
struct
dhcp_packet
*
mess
,
unsigned
char
*
agent_id
,
unsigned
char
*
real_end
)
{
{
unsigned
char
*
p
=
dhcp_skip_opts
(
&
mess
->
options
[
0
]
+
sizeof
(
u32
));
unsigned
char
*
p
=
dhcp_skip_opts
(
&
mess
->
options
[
0
]
+
sizeof
(
u32
));
...
@@ -2200,7 +2075,7 @@ static void do_options(struct dhcp_context *context,
...
@@ -2200,7 +2075,7 @@ static void do_options(struct dhcp_context *context,
unsigned
char
*
end
,
unsigned
char
*
end
,
unsigned
char
*
req_options
,
unsigned
char
*
req_options
,
char
*
hostname
,
char
*
hostname
,
char
*
domain
,
char
*
config_domain
,
char
*
domain
,
struct
dhcp_netid
*
netid
,
struct
dhcp_netid
*
netid
,
struct
in_addr
subnet_addr
,
struct
in_addr
subnet_addr
,
unsigned
char
fqdn_flags
,
unsigned
char
fqdn_flags
,
...
@@ -2219,65 +2094,21 @@ static void do_options(struct dhcp_context *context,
...
@@ -2219,65 +2094,21 @@ static void do_options(struct dhcp_context *context,
struct
dhcp_netid
*
tagif
;
struct
dhcp_netid
*
tagif
;
struct
dhcp_netid_list
*
id_list
;
struct
dhcp_netid_list
*
id_list
;
/* flag options which are valid with the current tag set (sans context tags) */
/* filter options based on tags, those we want get DHOPT_TAGOK bit set */
tagif
=
run_tag_if
(
netid
);
tagif
=
option_filter
(
netid
,
&
context
->
netid
,
config_opts
);
for
(
opt
=
config_opts
;
opt
;
opt
=
opt
->
next
)
{
opt
->
flags
&=
~
DHOPT_TAGOK
;
if
(
!
(
opt
->
flags
&
(
DHOPT_ENCAPSULATE
|
DHOPT_VENDOR
|
DHOPT_RFC3925
))
&&
match_netid
(
opt
->
netid
,
tagif
,
0
))
opt
->
flags
|=
DHOPT_TAGOK
;
}
/* now flag options which are valid, including the context tags,
otherwise valid options are inhibited if we found a higher priotity one above */
if
(
context
&&
context
->
netid
.
net
)
{
context
->
netid
.
next
=
netid
;
tagif
=
run_tag_if
(
&
context
->
netid
);
for
(
opt
=
config_opts
;
opt
;
opt
=
opt
->
next
)
if
(
!
(
opt
->
flags
&
(
DHOPT_ENCAPSULATE
|
DHOPT_VENDOR
|
DHOPT_RFC3925
|
DHOPT_TAGOK
))
&&
match_netid
(
opt
->
netid
,
tagif
,
0
))
{
struct
dhcp_opt
*
tmp
;
for
(
tmp
=
config_opts
;
tmp
;
tmp
=
tmp
->
next
)
if
(
tmp
->
opt
==
opt
->
opt
&&
opt
->
netid
&&
(
tmp
->
flags
&
DHOPT_TAGOK
))
break
;
if
(
!
tmp
)
opt
->
flags
|=
DHOPT_TAGOK
;
}
}
/* now flag untagged options which are not overridden by tagged ones */
for
(
opt
=
config_opts
;
opt
;
opt
=
opt
->
next
)
if
(
!
(
opt
->
flags
&
(
DHOPT_ENCAPSULATE
|
DHOPT_VENDOR
|
DHOPT_RFC3925
|
DHOPT_TAGOK
))
&&
!
opt
->
netid
)
{
struct
dhcp_opt
*
tmp
;
for
(
tmp
=
config_opts
;
tmp
;
tmp
=
tmp
->
next
)
if
(
tmp
->
opt
==
opt
->
opt
&&
(
tmp
->
flags
&
DHOPT_TAGOK
))
break
;
if
(
!
tmp
)
opt
->
flags
|=
DHOPT_TAGOK
;
else
if
(
!
tmp
->
netid
)
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"Ignoring duplicate dhcp-option %d"
),
tmp
->
opt
);
}
if
(
config_domain
&&
(
!
domain
||
!
hostname_isequal
(
domain
,
config_domain
)))
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"Ignoring domain %s for DHCP host name %s"
),
config_domain
,
hostname
);
/* logging */
/* logging */
if
(
option_bool
(
OPT_LOG_OPTS
)
&&
req_options
)
if
(
option_bool
(
OPT_LOG_OPTS
)
&&
req_options
)
{
{
char
*
q
=
daemon
->
namebuff
;
char
*
q
=
daemon
->
namebuff
;
for
(
i
=
0
;
req_options
[
i
]
!=
OPTION_END
;
i
++
)
for
(
i
=
0
;
req_options
[
i
]
!=
OPTION_END
;
i
++
)
{
{
char
*
s
=
option_string
(
req_options
[
i
],
NULL
,
NULL
);
char
*
s
=
option_string
(
AF_INET
,
req_options
[
i
],
NULL
,
0
,
NULL
,
0
);
q
+=
snprintf
(
q
,
MAXDNAME
-
(
q
-
daemon
->
namebuff
),
q
+=
snprintf
(
q
,
MAXDNAME
-
(
q
-
daemon
->
namebuff
),
"%d%s%s%s"
,
"%d%s%s%s"
,
req_options
[
i
],
req_options
[
i
],
s
?
":"
:
""
,
s
trlen
(
s
)
!=
0
?
":"
:
""
,
s
?
s
:
""
,
s
,
req_options
[
i
+
1
]
==
OPTION_END
?
""
:
", "
);
req_options
[
i
+
1
]
==
OPTION_END
?
""
:
", "
);
if
(
req_options
[
i
+
1
]
==
OPTION_END
||
(
q
-
daemon
->
namebuff
)
>
40
)
if
(
req_options
[
i
+
1
]
==
OPTION_END
||
(
q
-
daemon
->
namebuff
)
>
40
)
{
{
...
@@ -2514,8 +2345,8 @@ static void do_options(struct dhcp_context *context,
...
@@ -2514,8 +2345,8 @@ static void do_options(struct dhcp_context *context,
/* Now send options to be encapsulated in arbitrary options,
/* Now send options to be encapsulated in arbitrary options,
eg dhcp-option=encap:172,17,.......
eg dhcp-option=encap:172,17,.......
Also hand vendor-identifying vendor-encapsulated options,
Also hand
le
vendor-identifying vendor-encapsulated options,
dhcp-option =
rfc3925
-encap:13,17,.......
dhcp-option =
vi
-encap:13,17,.......
The may be more that one "outer" to do, so group
The may be more that one "outer" to do, so group
all the options which match each outer in turn. */
all the options which match each outer in turn. */
for
(
opt
=
config_opts
;
opt
;
opt
=
opt
->
next
)
for
(
opt
=
config_opts
;
opt
;
opt
=
opt
->
next
)
...
...
src/rfc3315.c
View file @
c6cc03ed
...
@@ -21,40 +21,1293 @@
...
@@ -21,40 +21,1293 @@
static
size_t
outpacket_counter
;
static
size_t
outpacket_counter
;
static
int
make_duid1
(
unsigned
short
type
,
unsigned
int
flags
,
char
*
mac
,
static
void
end_opt6
(
int
container
);
size_t
maclen
,
void
*
parm
);
static
int
save_counter
(
int
newval
);
static
void
do_options6
(
struct
dhcp_context
*
context
,
void
*
oro
);
static
void
*
expand
(
size_t
headroom
);
static
int
new_opt6
(
int
opt
);
static
void
*
put_opt6
(
void
*
data
,
size_t
len
);
static
void
put_opt6_short
(
unsigned
int
val
);
static
void
put_opt6_long
(
unsigned
int
val
);
static
void
put_opt6_string
(
char
*
s
);
static
int
dhcp6_maybe_relay
(
struct
in6_addr
*
link_address
,
struct
dhcp_netid
**
relay_tagsp
,
struct
dhcp_context
*
context
,
int
interface
,
char
*
iface_name
,
void
*
inbuff
,
size_t
sz
,
int
is_unicast
,
time_t
now
);
static
int
dhcp6_no_relay
(
int
msg_type
,
struct
dhcp_netid
*
tags
,
struct
dhcp_context
*
context
,
int
interface
,
char
*
iface_name
,
void
*
inbuff
,
size_t
sz
,
int
is_unicast
,
time_t
now
);
static
void
log6_packet
(
char
*
type
,
unsigned
char
*
clid
,
int
clid_len
,
struct
in6_addr
*
addr
,
int
xid
,
char
*
iface
,
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
);
#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
#define opt6_type(opt) (opt6_uint(opt, -4, 2))
#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
void
make_duid
(
time_t
now
)
size_t
dhcp6_reply
(
struct
dhcp_context
*
context
,
int
interface
,
char
*
iface_name
,
size_t
sz
,
int
is_unicast
,
time_t
now
)
{
{
iface_enumerate
(
AF_LOCAL
,
&
now
,
make_duid1
);
struct
dhcp_netid
*
relay_tags
=
NULL
;
struct
dhcp_vendor
*
vendor
;
/* Mark these so we only match each at most once, to avoid tangled linked lists */
for
(
vendor
=
daemon
->
dhcp_vendors
;
vendor
;
vendor
=
vendor
->
next
)
vendor
->
netid
.
next
=
&
vendor
->
netid
;
outpacket_counter
=
0
;
if
(
dhcp6_maybe_relay
(
NULL
,
&
relay_tags
,
context
,
interface
,
iface_name
,
daemon
->
dhcp_packet
.
iov_base
,
sz
,
is_unicast
,
now
))
return
outpacket_counter
;
if
(
!
daemon
->
duid
)
return
0
;
die
(
"Cannot create DHCPv6 server DUID"
,
NULL
,
EC_MISC
);
}
}
static
int
make_duid1
(
unsigned
short
type
,
unsigned
int
flags
,
char
*
mac
,
/* This cost me blood to write, it will probably cost you blood to understand - srk. */
size_t
maclen
,
void
*
parm
)
static
int
dhcp6_maybe_relay
(
struct
in6_addr
*
link_address
,
struct
dhcp_netid
**
relay_tagsp
,
struct
dhcp_context
*
context
,
int
interface
,
char
*
iface_name
,
void
*
inbuff
,
size_t
sz
,
int
is_unicast
,
time_t
now
)
{
{
/* create DUID as specified in RFC3315. We use the MAC of the
void
*
end
=
inbuff
+
sz
;
first interface we find that isn't loopback or P-to-P */
void
*
opts
=
inbuff
+
34
;
int
msg_type
=
*
((
unsigned
char
*
)
inbuff
);
unsigned
char
*
outmsgtypep
;
void
*
opt
;
struct
dhcp_vendor
*
vendor
;
/* if not an encaplsulated relayed message, just do the stuff */
if
(
msg_type
!=
DHCP6RELAYFORW
)
{
/* if link_address != NULL if points to the link address field of the
innermost nested RELAYFORW message, which is where we find the
address of the network on which we can allocate an address.
Recalculate the available contexts using that information. */
if
(
link_address
)
{
struct
dhcp_context
*
c
;
context
=
NULL
;
for
(
c
=
daemon
->
dhcp6
;
c
;
c
=
c
->
next
)
if
(
!
IN6_IS_ADDR_LOOPBACK
(
link_address
)
&&
!
IN6_IS_ADDR_LINKLOCAL
(
link_address
)
&&
!
IN6_IS_ADDR_MULTICAST
(
link_address
)
&&
is_same_net6
(
link_address
,
&
c
->
start6
,
c
->
prefix
)
&&
is_same_net6
(
link_address
,
&
c
->
end6
,
c
->
prefix
))
{
c
->
current
=
context
;
context
=
c
;
}
if
(
!
context
)
{
inet_ntop
(
AF_INET6
,
link_address
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"no address range available for DHCPv6 request from relay at %s"
),
daemon
->
addrbuff
);
return
0
;
}
}
if
(
!
context
)
{
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"no address range available for DHCPv6 request via %s"
),
iface_name
);
return
0
;
}
return
dhcp6_no_relay
(
msg_type
,
*
relay_tagsp
,
context
,
interface
,
iface_name
,
inbuff
,
sz
,
is_unicast
,
now
);
}
/* 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
)
return
0
;
unsigned
char
*
p
;
/* copy header stuff into reply message and set type to reply */
outmsgtypep
=
put_opt6
(
inbuff
,
34
);
*
outmsgtypep
=
DHCP6RELAYREPL
;
if
(
flags
&
(
IFF_LOOPBACK
|
IFF_POINTOPOINT
))
/* look for relay options and set tags if found. */
return
1
;
for
(
vendor
=
daemon
->
dhcp_vendors
;
vendor
;
vendor
=
vendor
->
next
)
{
int
mopt
;
if
(
vendor
->
match_type
==
MATCH_SUBSCRIBER
)
mopt
=
OPTION6_SUBSCRIBER_ID
;
else
if
(
vendor
->
match_type
==
MATCH_REMOTE
)
mopt
=
OPTION6_REMOTE_ID
;
else
continue
;
if
((
opt
=
opt6_find
(
opts
,
end
,
mopt
,
1
))
&&
vendor
->
len
==
opt6_len
(
opt
)
&&
memcmp
(
vendor
->
data
,
opt6_ptr
(
opt
,
0
),
vendor
->
len
)
==
0
&&
vendor
->
netid
.
next
!=
&
vendor
->
netid
)
{
vendor
->
netid
.
next
=
*
relay_tagsp
;
*
relay_tagsp
=
&
vendor
->
netid
;
break
;
}
}
for
(
opt
=
opts
;
opt
;
opt
=
opt6_next
(
opt
,
end
))
{
int
o
=
new_opt6
(
opt6_type
(
opt
));
if
(
opt6_type
(
opt
)
==
OPTION6_RELAY_MSG
)
{
struct
in6_addr
link_address
;
/* the packet data is unaligned, copy to aligned storage */
memcpy
(
&
link_address
,
inbuff
+
2
,
IN6ADDRSZ
);
/* Not, zero is_unicast since that is now known to refer to the
relayed packet, not the original sent by the client */
if
(
!
dhcp6_maybe_relay
(
&
link_address
,
relay_tagsp
,
context
,
interface
,
iface_name
,
opt6_ptr
(
opt
,
0
),
opt6_len
(
opt
),
0
,
now
))
return
0
;
}
else
put_opt6
(
opt6_ptr
(
opt
,
0
),
opt6_len
(
opt
));
end_opt6
(
o
);
}
daemon
->
duid
=
p
=
safe_malloc
(
maclen
+
8
);
return
1
;
daemon
->
duid_len
=
maclen
+
8
;
}
PUTSHORT
(
1
,
p
);
/* DUID_LLT */
PUTSHORT
(
type
,
p
);
/* address type */
PUTLONG
(
*
((
time_t
*
)
parm
),
p
);
/* time */
memcpy
(
p
,
mac
,
maclen
);
return
0
;
static
int
dhcp6_no_relay
(
int
msg_type
,
struct
dhcp_netid
*
tags
,
struct
dhcp_context
*
context
,
int
interface
,
char
*
iface_name
,
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
;
struct
dhcp_config
*
config
=
NULL
;
struct
dhcp_netid
known_id
,
iface_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 */
/* set tag with name == interface */
iface_id
.
net
=
iface_name
;
iface_id
.
next
=
tags
;
tags
=
&
iface_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
;
/* 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 */
for
(
context_tmp
=
context
;
context_tmp
;
context_tmp
=
context_tmp
->
current
)
{
context
->
netid
.
next
=
&
context
->
netid
;
if
(
option_bool
(
OPT_LOG_OPTS
))
{
inet_ntop
(
AF_INET6
,
&
context_tmp
->
start6
,
daemon
->
dhcp_buff
,
ADDRSTRLEN
);
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
);
else
my_syslog
(
MS_DHCP
|
LOG_INFO
,
_
(
"%u available DHCP range: %s -- %s"
),
xid
,
daemon
->
dhcp_buff
,
daemon
->
dhcp_buff2
);
}
}
if
((
opt
=
opt6_find
(
packet_options
,
end
,
OPTION6_CLIENT_ID
,
1
)))
{
clid
=
opt6_ptr
(
opt
,
0
);
clid_len
=
opt6_len
(
opt
);
o
=
new_opt6
(
OPTION6_CLIENT_ID
);
put_opt6
(
clid
,
clid_len
);
end_opt6
(
o
);
}
else
if
(
msg_type
!=
DHCP6IREQ
)
return
0
;
/* 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
))
||
opt6_len
(
opt
)
!=
daemon
->
duid_len
||
memcmp
(
opt6_ptr
(
opt
,
0
),
daemon
->
duid
,
daemon
->
duid_len
)
!=
0
))
return
0
;
o
=
new_opt6
(
OPTION6_SERVER_ID
);
put_opt6
(
daemon
->
duid
,
daemon
->
duid_len
);
end_opt6
(
o
);
if
(
is_unicast
&&
(
msg_type
==
DHCP6REQUEST
||
msg_type
==
DHCP6RENEW
||
msg_type
==
DHCP6RELEASE
||
msg_type
==
DHCP6DECLINE
))
{
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6USEMULTI
);
put_opt6_string
(
"Use multicast"
);
end_opt6
(
o1
);
return
1
;
}
/* match vendor and user class options */
for
(
vendor
=
daemon
->
dhcp_vendors
;
vendor
;
vendor
=
vendor
->
next
)
{
int
mopt
;
if
(
vendor
->
match_type
==
MATCH_VENDOR
)
mopt
=
OPTION6_VENDOR_CLASS
;
else
if
(
vendor
->
match_type
==
MATCH_USER
)
mopt
=
OPTION6_USER_CLASS
;
else
continue
;
if
((
opt
=
opt6_find
(
packet_options
,
end
,
mopt
,
2
)))
{
void
*
enc_opt
,
*
enc_end
=
opt6_ptr
(
opt
,
opt6_len
(
opt
));
int
offset
=
0
;
if
(
mopt
==
OPTION6_VENDOR_CLASS
)
{
if
(
opt6_len
(
opt
)
<
4
)
continue
;
if
(
vendor
->
enterprise
!=
opt6_uint
(
opt
,
0
,
4
))
continue
;
offset
=
4
;
}
for
(
enc_opt
=
opt6_ptr
(
opt
,
offset
);
enc_opt
;
enc_opt
=
opt6_next
(
enc_opt
,
enc_end
))
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
;
break
;
}
}
}
/* 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.
If no data given, existance of the option is enough. This code handles
V-I opts too. */
for
(
opt_cfg
=
daemon
->
dhcp_match6
;
opt_cfg
;
opt_cfg
=
opt_cfg
->
next
)
{
int
match
=
0
;
if
(
opt_cfg
->
flags
&
DHOPT_RFC3925
)
{
for
(
opt
=
opt6_find
(
packet_options
,
end
,
OPTION6_VENDOR_OPTS
,
4
);
opt
;
opt
=
opt6_find
(
opt6_next
(
opt
,
end
),
end
,
OPTION6_VENDOR_OPTS
,
4
))
{
void
*
vopt
;
void
*
vend
=
opt6_ptr
(
opt
,
opt6_len
(
opt
));
for
(
vopt
=
opt6_find
(
opt6_ptr
(
opt
,
4
),
vend
,
opt_cfg
->
opt
,
0
);
vopt
;
vopt
=
opt6_find
(
opt6_next
(
vopt
,
vend
),
vend
,
opt_cfg
->
opt
,
0
))
if
((
match
=
match_bytes
(
opt_cfg
,
opt6_ptr
(
vopt
,
0
),
opt6_len
(
vopt
))))
break
;
}
if
(
match
)
break
;
}
else
{
if
(
!
(
opt
=
opt6_find
(
packet_options
,
end
,
opt_cfg
->
opt
,
1
)))
continue
;
match
=
match_bytes
(
opt_cfg
,
opt6_ptr
(
opt
,
0
),
opt6_len
(
opt
));
}
if
(
match
)
{
opt_cfg
->
netid
->
next
=
tags
;
tags
=
opt_cfg
->
netid
;
}
}
if
((
opt
=
opt6_find
(
packet_options
,
end
,
OPTION6_FQDN
,
1
)))
{
/* RFC4704 refers */
int
len
=
opt6_len
(
opt
)
-
1
;
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
;
fqdn_flags
&=
~
0x04
;
if
(
len
!=
0
&&
len
<
255
)
{
unsigned
char
*
pp
,
*
op
=
opt6_ptr
(
opt
,
1
);
char
*
pq
=
daemon
->
dhcp_buff
;
pp
=
op
;
while
(
*
op
!=
0
&&
((
op
+
(
*
op
)
+
1
)
-
pp
)
<
len
)
{
memcpy
(
pq
,
op
+
1
,
*
op
);
pq
+=
*
op
;
op
+=
(
*
op
)
+
1
;
*
(
pq
++
)
=
'.'
;
}
if
(
pq
!=
daemon
->
dhcp_buff
)
pq
--
;
*
pq
=
0
;
if
(
legal_hostname
(
daemon
->
dhcp_buff
))
{
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
);
}
}
}
if
(
clid
)
{
config
=
find_config6
(
daemon
->
dhcp_conf
,
context
,
clid
,
clid_len
,
NULL
);
if
(
have_config
(
config
,
CONFIG_NAME
))
{
hostname
=
config
->
hostname
;
domain
=
config
->
domain
;
hostname_auth
=
1
;
}
else
if
(
client_hostname
)
{
domain
=
strip_hostname
(
client_hostname
);
if
(
strlen
(
client_hostname
)
!=
0
)
{
hostname
=
client_hostname
;
if
(
!
config
)
{
/* Search again now we have a hostname.
Only accept configs without CLID and HWADDR here, (they won't match)
to avoid impersonation by name. */
struct
dhcp_config
*
new
=
find_config6
(
daemon
->
dhcp_conf
,
context
,
NULL
,
0
,
hostname
);
if
(
new
&&
!
have_config
(
new
,
CONFIG_CLID
)
&&
!
new
->
hwaddr
)
config
=
new
;
}
}
}
}
if
(
config
)
{
struct
dhcp_netid_list
*
list
;
for
(
list
=
config
->
netid
;
list
;
list
=
list
->
next
)
{
list
->
list
->
next
=
tags
;
tags
=
list
->
list
;
}
/* set "known" tag for known hosts */
known_id
.
net
=
"known"
;
known_id
.
next
=
tags
;
tags
=
&
known_id
;
if
(
have_config
(
config
,
CONFIG_DISABLE
))
ignore
=
1
;
}
/* if all the netids in the ignore list are present, ignore this client */
if
(
daemon
->
dhcp_ignore
)
{
struct
dhcp_netid_list
*
id_list
;
tagif
=
run_tag_if
(
tags
);
for
(
id_list
=
daemon
->
dhcp_ignore
;
id_list
;
id_list
=
id_list
->
next
)
if
(
match_netid
(
id_list
->
list
,
tagif
,
0
))
ignore
=
1
;
}
switch
(
msg_type
)
{
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
;
if
(
rapid_commit
)
{
o
=
new_opt6
(
OPTION6_RAPID_COMMIT
);
end_opt6
(
o
);
}
/* set reply message type */
*
outmsgtypep
=
make_lease
?
DHCP6REPLY
:
DHCP6ADVERTISE
;
log6_packet
(
msg_type
==
DHCP6SOLICIT
?
"DHCPSOLICIT"
:
"DHCPREQUEST"
,
clid
,
clid_len
,
NULL
,
xid
,
iface_name
,
ignore
?
"ignored"
:
NULL
);
if
(
ignore
)
return
0
;
for
(
opt
=
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
end
))
{
int
iaid
,
ia_type
=
opt6_type
(
opt
);
void
*
ia_option
,
*
ia_end
;
unsigned
int
min_time
=
0xffffffff
;
int
t1cntr
;
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
;
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_find
(
opt6_ptr
(
opt
,
ia_type
==
OPTION6_IA_NA
?
12
:
4
),
ia_end
,
OPTION6_IAADDR
,
24
);
/* reset "USED" flags on leases */
lease6_find
(
NULL
,
0
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
NULL
);
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
);
}
while
(
1
)
{
struct
in6_addr
alloced_addr
,
*
addrp
=
NULL
;
u32
preferred_time
=
0
;
struct
dhcp_lease
*
lease
=
NULL
;
if
(
ia_option
)
{
struct
in6_addr
*
req_addr
=
opt6_ptr
(
ia_option
,
0
);
preferred_time
=
opt6_uint
(
ia_option
,
16
,
4
);
if
(
!
address6_available
(
context
,
req_addr
,
tags
))
{
if
(
msg_type
==
DHCP6REQUEST
)
{
/* host has a lease, but it's not on the correct link */
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6NOTONLINK
);
put_opt6_string
(
"Not on link"
);
end_opt6
(
o1
);
}
}
else
if
((
lease
=
lease6_find
(
NULL
,
0
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
req_addr
))
&&
(
clid_len
!=
lease
->
clid_len
||
memcmp
(
clid
,
lease
->
clid
,
clid_len
)
!=
0
))
{
/* Address leased to another DUID */
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6UNSPEC
);
put_opt6_string
(
"Address in use"
);
end_opt6
(
o1
);
}
else
addrp
=
req_addr
;
}
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
)
{
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
))
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"not using configured address %s because it is leased to %s"
),
daemon
->
addrbuff
,
print_mac
(
daemon
->
namebuff
,
ltmp
->
clid
,
ltmp
->
clid_len
));
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
addrp
=
&
config
->
addr6
;
}
/* existing lease */
if
(
!
addrp
&&
(
lease
=
lease6_find
(
clid
,
clid_len
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
NULL
))
&&
address6_available
(
context
,
(
struct
in6_addr
*
)
&
lease
->
hwaddr
,
tags
)
&&
!
config_find_by_address6
(
daemon
->
dhcp_conf
,
(
struct
in6_addr
*
)
&
lease
->
hwaddr
,
128
,
0
))
addrp
=
(
struct
in6_addr
*
)
&
lease
->
hwaddr
;
if
(
!
addrp
&&
address6_allocate
(
context
,
clid
,
clid_len
,
serial
++
,
tags
,
&
alloced_addr
))
addrp
=
&
alloced_addr
;
}
if
(
addrp
)
{
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
;
/* shouldn't ever fail */
if
((
this_context
=
narrow_context6
(
context
,
addrp
,
tags
)))
{
/* 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
;
}
lease_time
=
have_config
(
valid_config
,
CONFIG_TIME
)
?
valid_config
->
lease_time
:
this_context
->
lease_time
;
if
(
ia_option
)
{
if
(
preferred_time
<
120u
)
preferred_time
=
120u
;
/* sanity */
if
(
lease_time
==
0xffffffff
||
(
preferred_time
!=
0xffffffff
&&
preferred_time
<
lease_time
))
lease_time
=
preferred_time
;
}
if
(
lease_time
<
min_time
)
min_time
=
lease_time
;
/* May fail to create lease */
if
(
!
lease
&&
make_lease
)
lease
=
lease6_allocate
(
addrp
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
);
if
(
lease
)
{
lease_set_expires
(
lease
,
lease_time
,
now
);
lease_set_hwaddr
(
lease
,
NULL
,
clid
,
0
,
iaid
,
clid_len
);
lease_set_interface
(
lease
,
interface
);
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
((
class_opt
=
opt6_find
(
packet_options
,
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
*
)
client_hostname
,
client_hostname
?
strlen
(
client_hostname
)
:
0
,
0
);
/* space-concat tag set */
if
(
!
tags
)
lease_add_extradata
(
lease
,
NULL
,
0
,
0
);
else
{
struct
dhcp_netid
*
n
;
for
(
n
=
run_tag_if
(
tags
);
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
((
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
);
}
}
#endif
}
else
if
(
!
send_domain
)
send_domain
=
get_domain6
(
addrp
);
if
(
lease
||
!
make_lease
)
{
o1
=
new_opt6
(
OPTION6_IAADDR
);
put_opt6
(
addrp
,
sizeof
(
*
addrp
));
put_opt6_long
(
lease_time
);
put_opt6_long
(
lease_time
);
end_opt6
(
o1
);
log6_packet
(
make_lease
?
"DHCPREPLY"
:
"DHCPADVERTISE"
,
clid
,
clid_len
,
addrp
,
xid
,
iface_name
,
hostname
);
}
}
}
if
(
!
ia_option
||
!
(
ia_option
=
opt6_find
(
opt6_next
(
ia_option
,
ia_end
),
ia_end
,
OPTION6_IAADDR
,
24
)))
{
if
(
address_assigned
)
{
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
{
/* no address, return erro */
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6NOADDRS
);
put_opt6_string
(
"No addresses available"
);
end_opt6
(
o1
);
}
end_opt6
(
o
);
break
;
}
}
}
break
;
}
case
DHCP6RENEW
:
{
/* set reply message type */
*
outmsgtypep
=
DHCP6REPLY
;
log6_packet
(
"DHCPRENEW"
,
clid
,
clid_len
,
NULL
,
xid
,
iface_name
,
NULL
);
for
(
opt
=
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
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
;
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
);
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
);
}
iacntr
=
save_counter
(
-
1
);
/* reset "USED" flags on leases */
lease6_find
(
NULL
,
0
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
NULL
);
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
))
{
struct
dhcp_lease
*
lease
=
NULL
;
struct
in6_addr
*
req_addr
=
opt6_ptr
(
ia_option
,
0
);
u32
preferred_time
=
opt6_uint
(
ia_option
,
16
,
4
);
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
,
req_addr
,
IN6ADDRSZ
)
!=
0
)
valid_config
=
NULL
;
if
(
!
(
lease
=
lease6_find
(
clid
,
clid_len
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
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
to NoBinding in the Reply message. */
save_counter
(
iacntr
);
t1cntr
=
0
;
log6_packet
(
"DHCPREPLY"
,
clid
,
clid_len
,
req_addr
,
xid
,
iface_name
,
"lease not found"
);
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6NOBINDING
);
put_opt6_string
(
"No binding found"
);
end_opt6
(
o1
);
break
;
}
tagif
=
run_tag_if
(
tags
);
if
(
!
address6_available
(
context
,
req_addr
,
tagif
)
||
!
(
this_context
=
narrow_context6
(
context
,
req_addr
,
tagif
)))
lease_time
=
0
;
else
{
/* 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
;
}
lease_time
=
have_config
(
valid_config
,
CONFIG_TIME
)
?
valid_config
->
lease_time
:
this_context
->
lease_time
;
if
(
preferred_time
<
120u
)
preferred_time
=
120u
;
/* sanity */
if
(
lease_time
==
0xffffffff
||
(
preferred_time
!=
0xffffffff
&&
preferred_time
<
lease_time
))
lease_time
=
preferred_time
;
lease_set_expires
(
lease
,
lease_time
,
now
);
if
(
ia_type
==
OPTION6_IA_NA
&&
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
(
lease_time
<
min_time
)
min_time
=
lease_time
;
}
log6_packet
(
"DHCPREPLY"
,
clid
,
clid_len
,
req_addr
,
xid
,
iface_name
,
hostname
);
o1
=
new_opt6
(
OPTION6_IAADDR
);
put_opt6
(
req_addr
,
sizeof
(
*
req_addr
));
put_opt6_long
(
lease_time
);
put_opt6_long
(
lease_time
);
end_opt6
(
o1
);
}
if
(
t1cntr
!=
0
)
{
/* 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
);
}
end_opt6
(
o
);
}
break
;
}
case
DHCP6CONFIRM
:
{
/* set reply message type */
*
outmsgtypep
=
DHCP6REPLY
;
log6_packet
(
"DHCPCONFIRM"
,
clid
,
clid_len
,
NULL
,
xid
,
iface_name
,
NULL
);
for
(
opt
=
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
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
);
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
)))
{
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6NOTONLINK
);
put_opt6_string
(
"Confirm failed"
);
end_opt6
(
o1
);
return
1
;
}
log6_packet
(
"DHCPREPLY"
,
clid
,
clid_len
,
req_addr
,
xid
,
iface_name
,
hostname
);
}
}
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6SUCCESS
);
put_opt6_string
(
"All addresses still on link"
);
end_opt6
(
o1
);
return
1
;
}
case
DHCP6IREQ
:
{
if
(
ignore
)
return
0
;
*
outmsgtypep
=
DHCP6REPLY
;
break
;
}
case
DHCP6RELEASE
:
{
/* set reply message type */
*
outmsgtypep
=
DHCP6REPLY
;
log6_packet
(
"DHCPRELEASE"
,
clid
,
clid_len
,
NULL
,
xid
,
iface_name
,
NULL
);
for
(
opt
=
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
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_find
(
NULL
,
0
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
NULL
);
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
))
{
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
))))
lease_prune
(
lease
,
now
);
else
{
if
(
!
made_ia
)
{
o
=
new_opt6
(
ia_type
);
put_opt6_long
(
iaid
);
if
(
ia_type
==
OPTION6_IA_NA
)
{
put_opt6_long
(
0
);
put_opt6_long
(
0
);
}
made_ia
=
1
;
}
o1
=
new_opt6
(
OPTION6_IAADDR
);
put_opt6
(
opt6_ptr
(
ia_option
,
0
),
IN6ADDRSZ
);
put_opt6_long
(
0
);
put_opt6_long
(
0
);
end_opt6
(
o1
);
}
}
if
(
made_ia
)
{
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6NOBINDING
);
put_opt6_string
(
"No binding found"
);
end_opt6
(
o1
);
end_opt6
(
o
);
}
}
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6SUCCESS
);
put_opt6_string
(
"Release received"
);
end_opt6
(
o1
);
return
1
;
}
case
DHCP6DECLINE
:
{
/* set reply message type */
*
outmsgtypep
=
DHCP6REPLY
;
log6_packet
(
"DHCPDECLINE"
,
clid
,
clid_len
,
NULL
,
xid
,
iface_name
,
NULL
);
for
(
opt
=
packet_options
;
opt
;
opt
=
opt6_next
(
opt
,
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_find
(
NULL
,
0
,
ia_type
==
OPTION6_IA_NA
?
LEASE_NA
:
LEASE_TA
,
iaid
,
NULL
);
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
))
{
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
)
{
prettyprint_time
(
daemon
->
dhcp_buff3
,
DECLINE_BACKOFF
);
inet_ntop
(
AF_INET6
,
addrp
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
my_syslog
(
MS_DHCP
|
LOG_WARNING
,
_
(
"disabling DHCP static address %s for %s"
),
daemon
->
addrbuff
,
daemon
->
dhcp_buff3
);
config
->
flags
|=
CONFIG_DECLINED
;
config
->
decline_time
=
now
;
}
else
/* make sure this host gets a different address next time. */
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
))))
lease_prune
(
lease
,
now
);
else
{
if
(
!
made_ia
)
{
o
=
new_opt6
(
ia_type
);
put_opt6_long
(
iaid
);
if
(
ia_type
==
OPTION6_IA_NA
)
{
put_opt6_long
(
0
);
put_opt6_long
(
0
);
}
made_ia
=
1
;
}
o1
=
new_opt6
(
OPTION6_IAADDR
);
put_opt6
(
opt6_ptr
(
ia_option
,
0
),
IN6ADDRSZ
);
put_opt6_long
(
0
);
put_opt6_long
(
0
);
end_opt6
(
o1
);
}
}
if
(
made_ia
)
{
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6NOBINDING
);
put_opt6_string
(
"No binding found"
);
end_opt6
(
o1
);
end_opt6
(
o
);
}
}
return
1
;
}
}
/* filter options based on tags, those we want get DHOPT_TAGOK bit set */
tagif
=
option_filter
(
tags
,
context_tags
,
daemon
->
dhcp_opts6
);
oro
=
opt6_find
(
packet_options
,
end
,
OPTION6_ORO
,
0
);
for
(
opt_cfg
=
daemon
->
dhcp_opts6
;
opt_cfg
;
opt_cfg
=
opt_cfg
->
next
)
{
/* netids match and not encapsulated? */
if
(
!
(
opt_cfg
->
flags
&
DHOPT_TAGOK
))
continue
;
if
(
!
(
opt_cfg
->
flags
&
DHOPT_FORCE
)
&&
oro
)
{
for
(
i
=
0
;
i
<
opt6_len
(
oro
)
-
1
;
i
+=
2
)
if
(
opt6_uint
(
oro
,
i
,
2
)
==
(
unsigned
)
opt_cfg
->
opt
)
break
;
/* option not requested */
if
(
i
>=
opt6_len
(
oro
)
-
1
)
continue
;
}
if
(
opt_cfg
->
opt
==
OPTION6_DNS_SERVER
)
{
done_dns
=
1
;
if
(
opt_cfg
->
len
==
0
)
continue
;
}
o
=
new_opt6
(
opt_cfg
->
opt
);
/* Maye be empty */
if
(
opt_cfg
->
val
)
put_opt6
(
opt_cfg
->
val
,
opt_cfg
->
len
);
end_opt6
(
o
);
}
if
(
!
done_dns
)
{
o
=
new_opt6
(
OPTION6_DNS_SERVER
);
put_opt6
(
&
context
->
local6
,
IN6ADDRSZ
);
end_opt6
(
o
);
}
/* handle vendor-identifying vendor-encapsulated options,
dhcp-option = vi-encap:13,17,....... */
for
(
opt_cfg
=
daemon
->
dhcp_opts6
;
opt_cfg
;
opt_cfg
=
opt_cfg
->
next
)
opt_cfg
->
flags
&=
~
DHOPT_ENCAP_DONE
;
if
(
oro
)
for
(
i
=
0
;
i
<
opt6_len
(
oro
)
-
1
;
i
+=
2
)
if
(
opt6_uint
(
oro
,
i
,
2
)
==
OPTION6_VENDOR_OPTS
)
do_encap
=
1
;
for
(
opt_cfg
=
daemon
->
dhcp_opts6
;
opt_cfg
;
opt_cfg
=
opt_cfg
->
next
)
{
if
(
opt_cfg
->
flags
&
DHOPT_RFC3925
)
{
int
found
=
0
;
struct
dhcp_opt
*
oc
;
if
(
opt_cfg
->
flags
&
DHOPT_ENCAP_DONE
)
continue
;
for
(
oc
=
daemon
->
dhcp_opts6
;
oc
;
oc
=
oc
->
next
)
{
oc
->
flags
&=
~
DHOPT_ENCAP_MATCH
;
if
(
!
(
oc
->
flags
&
DHOPT_RFC3925
)
||
opt_cfg
->
u
.
encap
!=
oc
->
u
.
encap
)
continue
;
oc
->
flags
|=
DHOPT_ENCAP_DONE
;
if
(
match_netid
(
oc
->
netid
,
tagif
,
1
))
{
/* option requested/forced? */
if
(
!
oro
||
do_encap
||
(
oc
->
flags
&
DHOPT_FORCE
))
{
oc
->
flags
|=
DHOPT_ENCAP_MATCH
;
found
=
1
;
}
}
}
if
(
found
)
{
o
=
new_opt6
(
OPTION6_VENDOR_OPTS
);
put_opt6_long
(
opt_cfg
->
u
.
encap
);
for
(
oc
=
daemon
->
dhcp_opts6
;
oc
;
oc
=
oc
->
next
)
if
(
oc
->
flags
&
DHOPT_ENCAP_MATCH
)
{
o1
=
new_opt6
(
oc
->
opt
);
put_opt6
(
oc
->
val
,
oc
->
len
);
end_opt6
(
o1
);
}
end_opt6
(
o
);
}
}
}
if
(
hostname
)
{
unsigned
char
*
p
;
size_t
len
=
strlen
(
hostname
);
if
(
send_domain
)
len
+=
strlen
(
send_domain
)
+
1
;
o
=
new_opt6
(
OPTION6_FQDN
);
p
=
expand
(
len
+
3
);
*
(
p
++
)
=
fqdn_flags
;
p
=
do_rfc1035_name
(
p
,
hostname
);
if
(
send_domain
)
p
=
do_rfc1035_name
(
p
,
send_domain
);
*
p
=
0
;
end_opt6
(
o
);
}
/* logging */
if
(
option_bool
(
OPT_LOG_OPTS
)
&&
oro
)
{
char
*
q
=
daemon
->
namebuff
;
for
(
i
=
0
;
i
<
opt6_len
(
oro
)
-
1
;
i
+=
2
)
{
char
*
s
=
option_string
(
AF_INET6
,
opt6_uint
(
oro
,
i
,
2
),
NULL
,
0
,
NULL
,
0
);
q
+=
snprintf
(
q
,
MAXDNAME
-
(
q
-
daemon
->
namebuff
),
"%d%s%s%s"
,
opt6_uint
(
oro
,
i
,
2
),
strlen
(
s
)
!=
0
?
":"
:
""
,
s
,
(
i
>
opt6_len
(
oro
)
-
3
)
?
""
:
", "
);
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
);
}
}
}
log_tags
(
tagif
,
xid
);
if
(
option_bool
(
OPT_LOG_OPTS
))
{
int
end_opts
=
save_counter
(
-
1
);
/* must have created at least one option */
if
(
start_opts
!=
end_opts
)
for
(
opt
=
daemon
->
outpacket
.
iov_base
+
start_opts
;
opt
;
opt
=
opt6_next
(
opt
,
daemon
->
outpacket
.
iov_base
+
end_opts
))
{
int
offset
=
0
;
char
*
optname
;
/* account for flag byte on FQDN */
if
(
opt6_type
(
opt
)
==
OPTION6_FQDN
)
offset
=
1
;
optname
=
option_string
(
AF_INET6
,
opt6_type
(
opt
),
opt6_ptr
(
opt
,
offset
),
opt6_len
(
opt
)
-
offset
,
daemon
->
namebuff
,
MAXDNAME
);
my_syslog
(
MS_DHCP
|
LOG_INFO
,
"%u sent size:%3d option:%3d %s %s"
,
xid
,
opt6_len
(
opt
),
opt6_type
(
opt
),
optname
,
daemon
->
namebuff
);
}
}
return
1
;
}
static
void
log6_packet
(
char
*
type
,
unsigned
char
*
clid
,
int
clid_len
,
struct
in6_addr
*
addr
,
int
xid
,
char
*
iface
,
char
*
string
)
{
/* avoid buffer overflow */
if
(
clid_len
>
100
)
clid_len
=
100
;
print_mac
(
daemon
->
namebuff
,
clid
,
clid_len
);
if
(
addr
)
{
inet_ntop
(
AF_INET6
,
addr
,
daemon
->
dhcp_buff2
,
255
);
strcat
(
daemon
->
dhcp_buff2
,
" "
);
}
else
daemon
->
dhcp_buff2
[
0
]
=
0
;
if
(
option_bool
(
OPT_LOG_OPTS
))
my_syslog
(
MS_DHCP
|
LOG_INFO
,
"%u %s(%s) %s %s%s"
,
xid
,
type
,
iface
,
daemon
->
namebuff
,
daemon
->
dhcp_buff2
,
string
?
string
:
""
);
else
my_syslog
(
MS_DHCP
|
LOG_INFO
,
"%s(%s) %s %s%s"
,
type
,
iface
,
daemon
->
namebuff
,
daemon
->
dhcp_buff2
,
string
?
string
:
""
);
}
}
void
*
opt6_find
(
void
*
opts
,
void
*
end
,
unsigned
int
search
,
unsigned
int
minsize
)
static
void
*
opt6_find
(
void
*
opts
,
void
*
end
,
unsigned
int
search
,
unsigned
int
minsize
)
{
{
u16
opt
,
opt_len
;
u16
opt
,
opt_len
;
void
*
start
;
void
*
start
;
...
@@ -81,7 +1334,7 @@ void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsiz
...
@@ -81,7 +1334,7 @@ void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsiz
}
}
}
}
void
*
opt6_next
(
void
*
opts
,
void
*
end
)
static
void
*
opt6_next
(
void
*
opts
,
void
*
end
)
{
{
u16
opt_len
;
u16
opt_len
;
...
@@ -96,10 +1349,6 @@ void *opt6_next(void *opts, void *end)
...
@@ -96,10 +1349,6 @@ void *opt6_next(void *opts, void *end)
return
opts
+
opt_len
;
return
opts
+
opt_len
;
}
}
#define opt6_len(opt) (opt6_uint(opt, -2, 2))
#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
static
unsigned
int
opt6_uint
(
unsigned
char
*
opt
,
int
offset
,
int
size
)
static
unsigned
int
opt6_uint
(
unsigned
char
*
opt
,
int
offset
,
int
size
)
{
{
...
@@ -112,57 +1361,7 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
...
@@ -112,57 +1361,7 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
ret
=
(
ret
<<
8
)
|
*
p
++
;
ret
=
(
ret
<<
8
)
|
*
p
++
;
return
ret
;
return
ret
;
}
}
/*
set of routines to build arbitrarily nested options: eg
int o = new_opt(OPTION_IA_NA);
put_opt_long(IAID);
put_opt_long(T1);
put_opt_long(T2);
int o1 = new_opt(OPTION_IAADDR);
put_opt(o1, &addr, sizeof(addr));
put_opt_long(preferred_lifetime);
put_opt_long(valid_lifetime);
finalise_opt(o1);
finalise_opt(o);
to go back and fill in fields
int o = new_opt(OPTION_IA_NA);
put_opt_long(IAID);
int t1sav = save_counter(-1);
put_opt_long(0);
put_opt_long(0);
int o1 = new_opt(OPTION_IAADDR);
put_opt(o1, &addr, sizeof(addr));
put_opt_long(o1, preferred_lifetime);
put_opt_long(o1, valid_lifetime);
finalise_opt(o1);
int sav = save_counter(t1sav);
put_opt_long(T1);
save_counter(sav);
finalise_opt(o);
to abandon an option
int o = new_opt(OPTION_IA_NA);
put_opt_long(IAID);
put_opt_long(T1);
put_opt_long(T2);
if (err)
save_counter(o);
*/
static
void
end_opt6
(
int
container
)
static
void
end_opt6
(
int
container
)
{
{
...
@@ -172,7 +1371,7 @@ static void end_opt6(int container)
...
@@ -172,7 +1371,7 @@ static void end_opt6(int container)
PUTSHORT
(
len
,
p
);
PUTSHORT
(
len
,
p
);
}
}
static
int
save_counter
(
int
newval
)
static
int
save_counter
(
int
newval
)
{
{
int
ret
=
outpacket_counter
;
int
ret
=
outpacket_counter
;
if
(
newval
!=
-
1
)
if
(
newval
!=
-
1
)
...
@@ -181,8 +1380,6 @@ static int save_counter(int newval)
...
@@ -181,8 +1380,6 @@ static int save_counter(int newval)
return
ret
;
return
ret
;
}
}
static
void
*
expand
(
size_t
headroom
)
static
void
*
expand
(
size_t
headroom
)
{
{
void
*
ret
;
void
*
ret
;
...
@@ -211,14 +1408,11 @@ static int new_opt6(int opt)
...
@@ -211,14 +1408,11 @@ static int new_opt6(int opt)
return
ret
;
return
ret
;
}
}
static
void
*
put_opt6
(
void
*
data
,
size_t
len
)
static
void
*
put_opt6
(
void
*
data
,
size_t
len
)
{
{
void
*
p
;
void
*
p
;
if
(
data
&&
(
p
=
expand
(
len
)))
if
((
p
=
expand
(
len
)))
memcpy
(
p
,
data
,
len
);
memcpy
(
p
,
data
,
len
);
return
p
;
return
p
;
...
@@ -228,7 +1422,7 @@ static void put_opt6_long(unsigned int val)
...
@@ -228,7 +1422,7 @@ static void put_opt6_long(unsigned int val)
{
{
void
*
p
;
void
*
p
;
if
((
p
=
expand
(
4
)))
if
((
p
=
expand
(
4
)))
PUTLONG
(
val
,
p
);
PUTLONG
(
val
,
p
);
}
}
...
@@ -240,231 +1434,9 @@ static void put_opt6_short(unsigned int val)
...
@@ -240,231 +1434,9 @@ static void put_opt6_short(unsigned int val)
PUTSHORT
(
val
,
p
);
PUTSHORT
(
val
,
p
);
}
}
static
void
put_opt6_byte
(
unsigned
int
val
)
{
void
*
p
;
if
((
p
=
expand
(
1
)))
*
((
unsigned
char
*
)
p
)
=
val
;
}
static
void
put_opt6_string
(
char
*
s
)
static
void
put_opt6_string
(
char
*
s
)
{
{
put_opt6
(
s
,
strlen
(
s
));
put_opt6
(
s
,
strlen
(
s
));
}
}
size_t
dhcp6_reply
(
struct
dhcp_context
*
context
,
size_t
sz
,
time_t
now
)
{
void
*
packet_options
=
((
void
*
)
daemon
->
dhcp_packet
.
iov_base
)
+
4
;
void
*
end
=
((
void
*
)
daemon
->
dhcp_packet
.
iov_base
)
+
sz
;
void
*
na_option
,
*
na_end
;
void
*
opt
,
*
p
;
int
o
,
msg_type
=
*
((
unsigned
char
*
)
daemon
->
dhcp_packet
.
iov_base
);
int
make_lease
=
(
msg_type
==
DHCP6REQUEST
||
opt6_find
(
packet_options
,
end
,
OPTION6_RAPID_COMMIT
,
0
));
unsigned
char
*
clid
;
int
clid_len
;
struct
dhcp_netid
*
tags
;
/* copy over transaction-id */
memcpy
(
daemon
->
outpacket
.
iov_base
,
daemon
->
dhcp_packet
.
iov_base
,
4
);
/* set reply message type */
*
((
unsigned
char
*
)
daemon
->
outpacket
.
iov_base
)
=
make_lease
?
DHCP6REPLY
:
DHCP6ADVERTISE
;
/* skip message type and transaction-id */
outpacket_counter
=
4
;
if
(
!
(
opt
=
opt6_find
(
packet_options
,
end
,
OPTION6_CLIENT_ID
,
1
)))
return
0
;
clid
=
opt6_ptr
(
opt
,
0
);
clid_len
=
opt6_len
(
opt
);
o
=
new_opt6
(
OPTION6_CLIENT_ID
);
put_opt6
(
clid
,
clid_len
);
end_opt6
(
o
);
/* server-id must match except for SOLICIT meesages */
if
(
msg_type
!=
DHCP6SOLICIT
&&
(
!
(
opt
=
opt6_find
(
packet_options
,
end
,
OPTION6_SERVER_ID
,
1
))
||
opt6_len
(
opt
)
!=
daemon
->
duid_len
||
memcmp
(
opt6_ptr
(
opt
,
0
),
daemon
->
duid
,
daemon
->
duid_len
)
!=
0
))
return
0
;
o
=
new_opt6
(
OPTION6_SERVER_ID
);
put_opt6
(
daemon
->
duid
,
daemon
->
duid_len
);
end_opt6
(
o
);
switch
(
msg_type
)
{
case
DHCP6SOLICIT
:
case
DHCP6REQUEST
:
{
u16
*
req_options
=
NULL
;
for
(
opt
=
opt6_find
(
packet_options
,
end
,
OPTION6_IA_NA
,
12
);
opt
;
opt
=
opt6_find
(
opt6_next
(
opt
,
end
),
end
,
OPTION6_IA_NA
,
12
))
{
void
*
ia_end
=
opt6_ptr
(
opt
,
opt6_len
(
opt
));
void
*
ia_option
=
opt6_find
(
opt6_ptr
(
opt
,
12
),
ia_end
,
OPTION6_IAADDR
,
24
);
unsigned
int
min_time
=
0xffffffff
;
int
t1cntr
;
unsigned
int
iaid
=
opt6_uint
(
opt
,
0
,
4
);
int
address_assigned
=
0
;
struct
dhcp_lease
*
lease
=
NULL
;
o
=
new_opt6
(
OPTION6_IA_NA
);
put_opt6_long
(
iaid
);
/* save pointer */
t1cntr
=
save_counter
(
-
1
);
/* so we can fill these in later */
put_opt6_long
(
0
);
put_opt6_long
(
0
);
while
(
1
)
{
struct
in6_addr
alloced_addr
,
*
addrp
=
NULL
;
if
(
ia_option
)
{
struct
in6_addr
*
req_addr
=
opt6_ptr
(
ia_option
,
0
);
u32
preferred_lifetime
=
opt6_uint
(
ia_option
,
16
,
4
);
u32
valid_lifetime
=
opt6_uint
(
ia_option
,
20
,
4
);
if
((
lease
=
lease6_find_by_addr
(
req_addr
,
128
,
0
)))
{
/* check if existing lease for host */
if
(
clid_len
==
lease
->
clid_len
&&
memcmp
(
clid
,
lease
->
clid
,
clid_len
)
==
0
)
addrp
=
req_addr
;
}
else
if
(
address6_available
(
context
,
req_addr
,
tags
))
addrp
=
req_addr
;
}
else
{
/* must have an address to CONFIRM */
if
(
msg_type
==
DHCP6REQUEST
)
return
0
;
/* existing lease */
if
((
lease
=
lease6_find_by_client
(
clid
,
clid_len
,
iaid
)))
addrp
=
(
struct
in6_addr
*
)
&
lease
->
hwaddr
;
else
if
(
address6_allocate
(
context
,
clid
,
clid_len
,
tags
,
&
alloced_addr
))
addrp
=
&
alloced_addr
;
}
if
(
addrp
)
{
unsigned
int
lease_time
;
address_assigned
=
1
;
context
=
narrow_context6
(
context
,
addrp
,
tags
);
lease_time
=
context
->
lease_time
;
if
(
lease_time
<
min_time
)
min_time
=
lease_time
;
/* May fail to create lease */
if
(
!
lease
&&
make_lease
)
lease
=
lease6_allocate
(
addrp
);
if
(
lease
)
{
lease_set_expires
(
lease
,
lease_time
,
now
);
lease_set_hwaddr
(
lease
,
NULL
,
clid
,
0
,
iaid
,
clid_len
);
}
if
(
lease
||
!
make_lease
)
{
int
o1
=
new_opt6
(
OPTION6_IAADDR
);
put_opt6
(
addrp
,
sizeof
(
*
addrp
));
put_opt6_long
(
lease_time
);
put_opt6_long
(
lease_time
);
end_opt6
(
o1
);
}
}
if
(
!
ia_option
||
!
(
ia_option
=
opt6_find
(
opt6_next
(
ia_option
,
ia_end
),
ia_end
,
OPTION6_IAADDR
,
24
)))
{
if
(
address_assigned
)
{
/* 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
{
/* no address, return erro */
int
o1
=
new_opt6
(
OPTION6_STATUS_CODE
);
put_opt6_short
(
DHCP6NOADDRS
);
put_opt6_string
(
"No addresses available"
);
end_opt6
(
o1
);
}
end_opt6
(
o
);
break
;
}
}
}
/* same again for TA */
for
(
opt
=
packet_options
;
opt
;
opt
=
opt6_find
(
opt6_next
(
opt
,
end
),
end
,
OPTION6_IA_TA
,
4
))
{
}
do_options6
(
context
,
opt6_find
(
packet_options
,
end
,
OPTION6_ORO
,
0
));
}
}
return
outpacket_counter
;
}
/* TODO tags to select options, and encapsualted options. */
static
void
do_options6
(
struct
dhcp_context
*
context
,
void
*
oro
)
{
unsigned
char
*
req_options
=
NULL
;
int
req_options_len
,
i
,
o
;
struct
dhcp_opt
*
opt
,
*
config_opts
=
daemon
->
dhcp_opts6
;
if
(
oro
)
{
req_options
=
opt6_ptr
(
oro
,
0
);
req_options_len
=
opt6_len
(
oro
);
}
for
(
opt
=
config_opts
;
opt
;
opt
=
opt
->
next
)
{
if
(
req_options
)
{
/* required options are not aligned... */
for
(
i
=
0
;
i
<
req_options_len
-
1
;
i
+=
2
)
if
(((
req_options
[
i
]
<<
8
)
|
req_options
[
i
+
1
])
==
opt
->
opt
)
break
;
/* option not requested */
if
(
i
==
req_options_len
)
continue
;
}
o
=
new_opt6
(
opt
->
opt
);
put_opt6
(
opt
->
val
,
opt
->
len
);
end_opt6
(
o
);
}
}
#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