1 Star 0 Fork 2

cwg2022/WIDE-DHCPv6

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
dhcp6_ctlclient.c 14.49 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
/* $KAME: dhcp6_ctlclient.c,v 1.5 2005/01/12 06:06:11 suz Exp $ */
/*
* Copyright (C) 2004 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <err.h>
#include <control.h>
#include <auth.h>
#include <base64.h>
#define MD5_DIGESTLENGTH 16
#define DEFAULT_SERVER_KEYFILE SYSCONFDIR "/dhcp6sctlkey"
#define DEFAULT_CLIENT_KEYFILE SYSCONFDIR "/dhcp6cctlkey"
static char *ctladdr;
static char *ctlport;
static enum { CTLCLIENT, CTLSERVER } ctltype = CTLCLIENT;
static inline int put16 __P((char **, int *, u_int16_t));
static inline int put32 __P((char **, int *, u_int32_t));
static inline int putval __P((char **, int *, void *, size_t));
static int setup_auth __P((char *, struct keyinfo *, int *));
static int make_command __P((int, char **, char **, size_t *,
struct keyinfo *, int));
static int make_remove_command __P((int, char **, char **, int *));
static int make_start_command __P((int, char **, char **, int *));
static int make_stop_command __P((int, char **, char **, int *));
static int make_binding_object __P((int, char **, char **, int *));
static int make_interface_object __P((int, char **, char **, int *));
static int make_ia_object __P((int, char **, char **, int *));
static int parse_duid __P((char *, int *, char **, int *));
static void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
int cc, ch, s, error, passed;
int Cflag = 0, Sflag = 0;
char *cbuf;
size_t clen;
struct addrinfo hints, *res0, *res;
int digestlen;
char *keyfile = NULL;
struct keyinfo key;
while ((ch = getopt(argc, argv, "CSa:k:p:")) != -1) {
switch (ch) {
case 'C':
if (Sflag)
errx(1, "-C and -S are exclusive");
Cflag = 1;
ctltype = CTLCLIENT;
break;
case 'S':
if (Cflag)
errx(1, "-C and -S are exclusive");
Sflag = 1;
ctltype = CTLSERVER;
break;
case 'a':
ctladdr = optarg;
break;
case 'k':
keyfile = optarg;
break;
case 'p':
ctlport = optarg;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc == 0)
usage();
switch (ctltype) {
case CTLCLIENT:
if (ctladdr == NULL)
ctladdr = DEFAULT_CLIENT_CONTROL_ADDR;
if (ctlport == NULL)
ctlport = DEFAULT_CLIENT_CONTROL_PORT;
if (keyfile == NULL)
keyfile = DEFAULT_CLIENT_KEYFILE;
break;
case CTLSERVER:
if (ctladdr == NULL)
ctladdr = DEFAULT_SERVER_CONTROL_ADDR;
if (ctlport == NULL)
ctlport = DEFAULT_SERVER_CONTROL_PORT;
if (keyfile == NULL)
keyfile = DEFAULT_SERVER_KEYFILE;
break;
}
memset(&key, 0, sizeof(key));
digestlen = 0;
if (setup_auth(keyfile, &key, &digestlen) != 0)
errx(1, "failed to setup message authentication");
if ((passed = make_command(argc, argv, &cbuf, &clen,
&key, digestlen)) < 0) {
errx(1, "failed to make command buffer");
}
argc -= passed;
argv += passed;
if (argc != 0)
warnx("redundant command argument after \"%s\"", argv[0]);
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
error = getaddrinfo(ctladdr, ctlport, &hints, &res0);
if (error != 0)
errx(1, "getaddrinfo failed: %s", gai_strerror(error));
s = -1;
for (res = res0; res != NULL; res = res->ai_next) {
s = socket(res->ai_family, res->ai_socktype,
res->ai_protocol);
if (s < 0) {
warn("socket");
continue;
}
if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
warn("connect");
s = -1;
continue;
}
break;
}
freeaddrinfo(res0);
if (s < 0) {
warnx("failed to connect to the %s",
ctltype == CTLCLIENT ? "client" : "server");
exit(1);
}
cc = write(s, cbuf, clen);
if (cc < 0)
err(1, "write command");
if (cc != clen)
errx(1, "failed to send complete command");
close(s);
free(cbuf);
exit(0);
}
static int
setup_auth(keyfile, key, digestlenp)
char *keyfile;
struct keyinfo *key;
int *digestlenp;
{
FILE *fp = NULL;
char line[1024], secret[1024];
int secretlen;
key->secret = NULL;
/* Currently, we only support HMAC-MD5 for authentication. */
*digestlenp = MD5_DIGESTLENGTH;
if ((fp = fopen(keyfile, "r")) == NULL) {
warn("fopen: %s", keyfile);
return (-1);
}
if (fgets(line, sizeof(line), fp) == NULL && ferror(fp)) {
warn("fgets failed");
goto fail;
}
if ((secretlen = base64_decodestring(line, secret, sizeof(secret)))
< 0) {
warnx("failed to decode base64 string");
goto fail;
}
if ((key->secret = malloc(secretlen)) == NULL) {
warn("setup_auth: malloc failed");
goto fail;
}
key->secretlen = (size_t)secretlen;
memcpy(key->secret, secret, secretlen);
fclose(fp);
return (0);
fail:
if (fp != NULL)
fclose(fp);
if (key->secret != NULL)
free(key->secret);
return (-1);
}
static inline int
put16(bpp, lenp, val)
char **bpp;
int *lenp;
u_int16_t val;
{
char *bp = *bpp;
int len = *lenp;
if (len < sizeof(val))
return (-1);
val = htons(val);
memcpy(bp, &val, sizeof(val));
bp += sizeof(val);
len -= sizeof(val);
*bpp = bp;
*lenp = len;
return (0);
}
static inline int
put32(bpp, lenp, val)
char **bpp;
int *lenp;
u_int32_t val;
{
char *bp = *bpp;
int len = *lenp;
if (len < sizeof(val))
return (-1);
val = htonl(val);
memcpy(bp, &val, sizeof(val));
bp += sizeof(val);
len -= sizeof(val);
*bpp = bp;
*lenp = len;
return (0);
}
static inline int
putval(bpp, lenp, val, valsize)
char **bpp;
int *lenp;
void *val;
size_t valsize;
{
char *bp = *bpp;
int len = *lenp;
if (len < valsize)
return (-1);
memcpy(bp, val, valsize);
bp += valsize;
len -= valsize;
*bpp = bp;
*lenp = len;
return (0);
}
static int
make_command(argc, argv, bufp, lenp, key, authlen)
int argc;
char **argv, **bufp;
size_t *lenp;
struct keyinfo *key;
int authlen;
{
struct dhcp6ctl ctl;
char commandbuf[4096]; /* XXX: ad-hoc value */
char *bp, *buf, *mac;
int buflen, len;
int argc_passed = 0, passed;
time_t now;
if (argc == 0) {
warnx("command is too short");
return (-1);
}
bp = commandbuf + sizeof(ctl) + authlen;
if (bp >= commandbuf + sizeof(commandbuf)) {
warnx("make_command: local buffer is too short");
return (-1);
}
buflen = sizeof(commandbuf) - sizeof(ctl);
memset(&ctl, 0, sizeof(ctl));
ctl.version = htons(DHCP6CTL_VERSION);
if (strcmp(argv[0], "reload") == 0)
ctl.command = htons(DHCP6CTL_COMMAND_RELOAD);
else if (strcmp(argv[0], "remove") == 0) {
if (ctltype != CTLSERVER) {
warnx("remove command is only for server");
return (-1);
}
if ((passed = make_remove_command(argc - 1, argv + 1,
&bp, &buflen)) < 0) {
return (-1);
}
argc_passed += passed;
ctl.command = htons(DHCP6CTL_COMMAND_REMOVE);
} else if (strcmp(argv[0], "start") == 0) {
if ((passed = make_start_command(argc - 1, argv + 1,
&bp, &buflen)) < 0) {
return (-1);
}
argc_passed += passed;
ctl.command = htons(DHCP6CTL_COMMAND_START);
} else if (strcmp(argv[0], "stop") == 0) {
if ((passed = make_stop_command(argc - 1, argv + 1,
&bp, &buflen)) < 0) {
return (-1);
}
argc_passed += passed;
ctl.command = htons(DHCP6CTL_COMMAND_STOP);
} else {
warnx("unknown command: %s", argv[0]);
return (-1);
}
len = bp - commandbuf;
ctl.len = htons(len - sizeof(ctl));
if ((now = time(NULL)) < 0) {
warn("failed to get current time");
return (-1);
}
ctl.timestamp = htonl((u_int32_t)now);
memcpy(commandbuf, &ctl, sizeof(ctl));
mac = commandbuf + sizeof(ctl);
memset(mac, 0, authlen);
if (dhcp6_calc_mac(commandbuf, len, DHCP6CTL_AUTHPROTO_UNDEF,
DHCP6CTL_AUTHALG_HMACMD5, sizeof(ctl), key) != 0) {
warnx("failed to calculate MAC");
return (-1);
}
if ((buf = malloc(len)) == NULL) {
warn("memory allocation failed");
return (-1);
}
memcpy(buf, commandbuf, len);
*lenp = len;
*bufp = buf;
argc_passed++;
return (argc_passed);
}
static int
make_remove_command(argc, argv, bpp, lenp)
int argc, *lenp;
char **argv, **bpp;
{
int argc_passed = 0, passed;
if (argc == 0) {
warnx("make_remove_command: command is too short");
return (-1);
}
if (strcmp(argv[0], "binding") == 0) {
if (put32(bpp, lenp, DHCP6CTL_BINDING))
goto fail;
if ((passed = make_binding_object(argc - 1, argv + 1,
bpp, lenp)) < 0) {
return (-1);
}
argc_passed += passed;
} else {
warnx("remove target not supported: %s", argv[0]);
return (-1);
}
argc_passed++;
return (argc_passed);
fail:
warnx("make_remove_command failed");
return (-1);
}
static int
make_start_command(argc, argv, bpp, lenp)
int argc, *lenp;
char **argv, **bpp;
{
int argc_passed = 0, passed;
if (argc == 0) {
warnx("make_remove_command: command is too short");
return (-1);
}
if (ctltype != CTLCLIENT) {
warnx("client-only command is specified for a server");
return (-1);
}
if (strcmp(argv[0], "interface") == 0) {
if (put32(bpp, lenp, DHCP6CTL_INTERFACE))
goto fail;
if ((passed = make_interface_object(argc - 1, argv + 1,
bpp, lenp)) < 0) {
return (-1);
}
argc_passed += passed;
} else {
warnx("start target not supported: %s", argv[0]);
return (-1);
}
argc_passed++;
return (argc_passed);
fail:
warnx("make_start_command failed");
return (-1);
}
static int
make_stop_command(argc, argv, bpp, lenp)
int argc, *lenp;
char **argv, **bpp;
{
int argc_passed = 0, passed;
if (argc == 0)
return (0);
if (ctltype != CTLCLIENT) {
warnx("client-only command is specified for a server");
return (-1);
}
if (strcmp(argv[0], "interface") == 0) {
if (put32(bpp, lenp, DHCP6CTL_INTERFACE))
goto fail;
if ((passed = make_interface_object(argc - 1, argv + 1,
bpp, lenp)) < 0) {
return (-1);
}
argc_passed += passed;
} else {
warnx("stop target not supported: %s", argv[0]);
return (-1);
}
argc_passed++;
return (argc_passed);
fail:
warnx("make_stop_command failed");
return (-1);
}
static int
make_interface_object(argc, argv, bpp, lenp)
int argc, *lenp;
char **argv, **bpp;
{
int iflen;
int argc_passed = 0;
if (argc == 0) {
warnx("make_interface_object: interface not specified");
return (-1);
}
argc_passed++;
iflen = strlen(argv[0]) + 1;
if (put32(bpp, lenp, (u_int32_t)iflen))
goto fail;
if (putval(bpp, lenp, argv[0], strlen(argv[0]) + 1))
goto fail;
return (argc_passed);
fail:
warnx("make_interface_object: failed");
return (-1);
}
static int
make_binding_object(argc, argv, bpp, lenp)
int argc, *lenp;
char **argv, **bpp;
{
int argc_passed = 0, passed;
if (argc == 0) {
/* or allow this as "all"? */
warnx("make_binding_object: command is too short");
return (-1);
}
if (strcmp(argv[0], "IA") == 0) {
if (put32(bpp, lenp, DHCP6CTL_BINDING_IA))
goto fail;
if ((passed = make_ia_object(argc - 1, argv + 1,
bpp, lenp)) < 0) {
return (-1);
}
argc_passed += passed;
} else {
warn("unknown binding type: %s", argv[0]);
return (-1);
}
argc_passed++;
return (argc_passed);
fail:
warnx("make_binding_object: failed");
return (-1);
}
static int
make_ia_object(argc, argv, bpp, lenp)
int argc, *lenp;
char **argv, **bpp;
{
struct dhcp6ctl_iaspec iaspec;
int duidlen, dummylen = 0;
int argc_passed = 0;
char *dummy = NULL;
if (argc < 3) {
/*
* Right now, we require all three parameters of
* <IA type, IAID, DUID>. This should be more flexible in
* the future.
*/
warnx("command is too short for an IA spec");
return (-1);
}
argc_passed += 3;
memset(&iaspec, 0, sizeof(iaspec));
if (strcmp(argv[0], "IA_PD") == 0)
iaspec.type = htonl(DHCP6CTL_IA_PD);
else if (strcmp(argv[0], "IA_NA") == 0)
iaspec.type = htonl(DHCP6CTL_IA_NA);
else {
warnx("IA type not supported: %s", argv[0]);
return (-1);
}
iaspec.id = htonl((u_int32_t)strtol(argv[1], NULL, 10));
if (parse_duid(argv[2], &duidlen, &dummy, &dummylen))
goto fail;
iaspec.duidlen = htonl(duidlen);
if (putval(bpp, lenp, &iaspec, sizeof(iaspec)))
goto fail;
if (parse_duid(argv[2], &duidlen, bpp, lenp))
goto fail;
return (argc_passed);
fail:
warnx("make_ia_object: failed");
return (-1);
}
static int
parse_duid(str, lenp, bufp, buflenp)
char *str;
int *lenp;
char **bufp;
int *buflenp;
{
char *buf = *bufp;
char *cp, *bp;
int duidlen, slen, buflen;
unsigned int x;
/* calculate DUID len */
slen = strlen(str);
if (slen < 2)
goto bad;
duidlen = 1;
slen -= 2;
if ((slen % 3) != 0)
goto bad;
duidlen += (slen / 3);
if (duidlen > 128) {
warn("too long DUID (%d bytes)", duidlen);
return (-1);
}
*lenp = duidlen;
if (buf == NULL)
return (0);
buflen = *buflenp;
if (buflen < duidlen)
goto bad;
for (cp = str, bp = buf; *cp != '\0';) {
if (bp - buf >= buflen)
goto bad;
if (sscanf(cp, "%02x", &x) != 1)
goto bad;
*bp++ = x;
cp += 2;
switch (*cp) {
case ':':
cp++;
break;
case '\0':
goto done;
default:
goto bad;
}
}
done:
*bufp = bp;
return (0);
bad:
return (-1);
}
static void
usage()
{
fprintf(stderr, "usage: dhcp6ctl [-C|-S] [-a ctladdr] [-k keyfile] "
"[-p ctlport] command...\n");
exit(1);
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/cwg2022/wide-dhcpv6.git
git@gitee.com:cwg2022/wide-dhcpv6.git
cwg2022
wide-dhcpv6
WIDE-DHCPv6
master

搜索帮助