typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
+typedef uint64_t flex_uint64_t;
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
#endif
/* %if-not-reentrant */
-extern int yyleng;
+extern yy_size_t yyleng;
/* %endif */
/* %if-c-only */
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
- int yy_n_chars;
+ yy_size_t yy_n_chars;
/* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to
/* %not-for-header */
/* yy_hold_char holds the character lost when yytext is formed. */
static char yy_hold_char;
-static int yy_n_chars; /* number of characters read into yy_ch_buf */
-int yyleng;
+static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+yy_size_t yyleng;
/* Points to current character in buffer. */
static char *yy_c_buf_p = NULL;
YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size );
YY_BUFFER_STATE yy_scan_string ( const char *yy_str );
-YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, yy_size_t len );
/* %endif */
#define YY_DO_BEFORE_ACTION \
(yytext_ptr) = yy_bp; \
/* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\
- yyleng = (int) (yy_cp - yy_bp); \
+ yyleng = (yy_size_t) (yy_cp - yy_bp); \
(yy_hold_char) = *yy_cp; \
*yy_cp = '\0'; \
/* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\
/* To avoid the call to exit... oops! */
#define YY_FATAL_ERROR(msg) isc::d2::D2ParserContext::fatal(msg)
-#line 1215 "d2_lexer.cc"
+#line 1216 "d2_lexer.cc"
/* noyywrap disables automatic rewinding for the next file to parse. Since we
always parse only a single string, there's no need to do any wraps. And
using yywrap requires linking with -lfl, which provides the default yywrap
by moving it ahead by yyleng bytes. yyleng specifies the length of the
currently matched token. */
#define YY_USER_ACTION driver.loc_.columns(yyleng);
-#line 1241 "d2_lexer.cc"
#line 1242 "d2_lexer.cc"
+#line 1243 "d2_lexer.cc"
#define INITIAL 0
#define COMMENT 1
void yyset_out ( FILE * _out_str );
- int yyget_leng ( void );
+ yy_size_t yyget_leng ( void );
char *yyget_text ( void );
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \
int c = '*'; \
- int n; \
+ yy_size_t n; \
for ( n = 0; n < max_size && \
(c = getc( yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
}
-#line 1562 "d2_lexer.cc"
+#line 1563 "d2_lexer.cc"
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
{
switch(driver.ctx_) {
case isc::d2::D2ParserContext::DHCPDDNS:
- return isc::d2::D2Parser::make_CONTROL_SOCKET(driver.loc_);
+ return isc::d2::D2Parser::make_CONTROL_SOCKETS(driver.loc_);
default:
- return isc::d2::D2Parser::make_STRING("control-socket", driver.loc_);
+ return isc::d2::D2Parser::make_STRING("control-sockets", driver.loc_);
}
}
YY_BREAK
#line 497 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CONTROL_SOCKET:
+ case isc::d2::D2ParserContext::CONTROL_SOCKET:
return isc::d2::D2Parser::make_AUTHENTICATION(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("authentication", driver.loc_);
#line 506 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::AUTHENTICATION:
+ case isc::d2::D2ParserContext::AUTHENTICATION:
return isc::d2::D2Parser::make_TYPE(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("type", driver.loc_);
#line 515 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::AUTH_TYPE:
+ case isc::d2::D2ParserContext::AUTH_TYPE:
return isc::d2::D2Parser::make_BASIC(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("basic", driver.loc_);
#line 524 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::AUTHENTICATION:
+ case isc::d2::D2ParserContext::AUTHENTICATION:
return isc::d2::D2Parser::make_REALM(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("realm", driver.loc_);
#line 533 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::AUTHENTICATION:
+ case isc::d2::D2ParserContext::AUTHENTICATION:
return isc::d2::D2Parser::make_DIRECTORY(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("directory", driver.loc_);
#line 542 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::AUTHENTICATION:
+ case isc::d2::D2ParserContext::AUTHENTICATION:
return isc::d2::D2Parser::make_CLIENTS(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("clients", driver.loc_);
#line 551 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CLIENTS:
+ case isc::d2::D2ParserContext::CLIENTS:
return isc::d2::D2Parser::make_USER(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("user", driver.loc_);
#line 560 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CLIENTS:
+ case isc::d2::D2ParserContext::CLIENTS:
return isc::d2::D2Parser::make_USER_FILE(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("user-file", driver.loc_);
#line 569 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CLIENTS:
+ case isc::d2::D2ParserContext::CLIENTS:
return isc::d2::D2Parser::make_PASSWORD(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("password", driver.loc_);
#line 578 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CLIENTS:
+ case isc::d2::D2ParserContext::CLIENTS:
return isc::d2::D2Parser::make_PASSWORD_FILE(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("password-file", driver.loc_);
#line 587 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CONTROL_SOCKET:
+ case isc::d2::D2ParserContext::CONTROL_SOCKET:
return isc::d2::D2Parser::make_TRUST_ANCHOR(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("trust-anchor", driver.loc_);
#line 596 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CONTROL_SOCKET:
+ case isc::d2::D2ParserContext::CONTROL_SOCKET:
return isc::d2::D2Parser::make_CERT_FILE(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("cert-file", driver.loc_);
#line 605 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CONTROL_SOCKET:
+ case isc::d2::D2ParserContext::CONTROL_SOCKET:
return isc::d2::D2Parser::make_KEY_FILE(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("key-file", driver.loc_);
#line 614 "d2_lexer.ll"
{
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CONTROL_SOCKET:
+ case isc::d2::D2ParserContext::CONTROL_SOCKET:
return isc::d2::D2Parser::make_CERT_REQUIRED(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("cert-required", driver.loc_);
#line 1020 "d2_lexer.ll"
ECHO;
YY_BREAK
-#line 2813 "d2_lexer.cc"
+#line 2814 "d2_lexer.cc"
case YY_END_OF_BUFFER:
{
else
{
- int num_to_read =
+ yy_size_t num_to_read =
YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
while ( num_to_read <= 0 )
if ( b->yy_is_our_buffer )
{
- int new_size = b->yy_buf_size * 2;
+ yy_size_t new_size = b->yy_buf_size * 2;
if ( new_size <= 0 )
b->yy_buf_size += b->yy_buf_size / 8;
if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
/* Extend the array by 50%, plus the number we really need. */
- int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
(void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size );
if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
else
{ /* need more input */
- int offset = (int) ((yy_c_buf_p) - (yytext_ptr));
+ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
++(yy_c_buf_p);
switch ( yy_get_next_buffer( ) )
*
* @return the newly allocated buffer state object.
*/
-YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len )
+YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, yy_size_t _yybytes_len )
{
YY_BUFFER_STATE b;
char *buf;
yy_size_t n;
- int i;
+ yy_size_t i;
/* Get memory for full buffer, including space for trailing EOB's. */
n = (yy_size_t) (_yybytes_len + 2);
do \
{ \
/* Undo effects of setting up yytext. */ \
- int yyless_macro_arg = (n); \
+ yy_size_t yyless_macro_arg = (n); \
YY_LESS_LINENO(yyless_macro_arg);\
yytext[yyleng] = (yy_hold_char); \
(yy_c_buf_p) = yytext + yyless_macro_arg; \
/** Get the length of the current token.
*
*/
-int yyget_leng (void)
+yy_size_t yyget_leng (void)
{
return yyleng;
}
\"control-sockets\" {
switch(driver.ctx_) {
case isc::d2::D2ParserContext::DHCPDDNS:
- return isc::d2::D2Parser::make_CONTROL_SOCKET(driver.loc_);
+ return isc::d2::D2Parser::make_CONTROL_SOCKETS(driver.loc_);
default:
- return isc::d2::D2Parser::make_STRING("control-socket", driver.loc_);
+ return isc::d2::D2Parser::make_STRING("control-sockets", driver.loc_);
}
}
\"authentication\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CONTROL_SOCKET:
+ case isc::d2::D2ParserContext::CONTROL_SOCKET:
return isc::d2::D2Parser::make_AUTHENTICATION(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("authentication", driver.loc_);
\"type\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::AUTHENTICATION:
+ case isc::d2::D2ParserContext::AUTHENTICATION:
return isc::d2::D2Parser::make_TYPE(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("type", driver.loc_);
\"basic\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::AUTH_TYPE:
+ case isc::d2::D2ParserContext::AUTH_TYPE:
return isc::d2::D2Parser::make_BASIC(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("basic", driver.loc_);
\"realm\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::AUTHENTICATION:
+ case isc::d2::D2ParserContext::AUTHENTICATION:
return isc::d2::D2Parser::make_REALM(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("realm", driver.loc_);
\"directory\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::AUTHENTICATION:
+ case isc::d2::D2ParserContext::AUTHENTICATION:
return isc::d2::D2Parser::make_DIRECTORY(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("directory", driver.loc_);
\"clients\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::AUTHENTICATION:
+ case isc::d2::D2ParserContext::AUTHENTICATION:
return isc::d2::D2Parser::make_CLIENTS(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("clients", driver.loc_);
\"user\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CLIENTS:
+ case isc::d2::D2ParserContext::CLIENTS:
return isc::d2::D2Parser::make_USER(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("user", driver.loc_);
\"user-file\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CLIENTS:
+ case isc::d2::D2ParserContext::CLIENTS:
return isc::d2::D2Parser::make_USER_FILE(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("user-file", driver.loc_);
\"password\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CLIENTS:
+ case isc::d2::D2ParserContext::CLIENTS:
return isc::d2::D2Parser::make_PASSWORD(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("password", driver.loc_);
\"password-file\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CLIENTS:
+ case isc::d2::D2ParserContext::CLIENTS:
return isc::d2::D2Parser::make_PASSWORD_FILE(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("password-file", driver.loc_);
\"trust-anchor\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CONTROL_SOCKET:
+ case isc::d2::D2ParserContext::CONTROL_SOCKET:
return isc::d2::D2Parser::make_TRUST_ANCHOR(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("trust-anchor", driver.loc_);
\"cert-file\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CONTROL_SOCKET:
+ case isc::d2::D2ParserContext::CONTROL_SOCKET:
return isc::d2::D2Parser::make_CERT_FILE(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("cert-file", driver.loc_);
\"key-file\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CONTROL_SOCKET:
+ case isc::d2::D2ParserContext::CONTROL_SOCKET:
return isc::d2::D2Parser::make_KEY_FILE(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("key-file", driver.loc_);
\"cert-required\" {
switch(driver.ctx_) {
- case isc::dhcp::Parser4Context::CONTROL_SOCKET:
+ case isc::d2::D2ParserContext::CONTROL_SOCKET:
return isc::d2::D2Parser::make_CERT_REQUIRED(driver.loc_);
default:
return isc::d2::D2Parser::make_STRING("cert-required", driver.loc_);
-// Copyright (C) 2017-2022 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
return("dns-servers");
case CONTROL_SOCKET:
return("control-socket");
+ case CONTROL_SOCKET_TYPE:
+ return ("control-socket-type");
+ case AUTHENTICATION:
+ return ("authentication");
+ case AUTH_TYPE:
+ return ("auth-type");
+ case CLIENTS:
+ return ("clients");
case LOGGERS:
return ("loggers");
case OUTPUT_OPTIONS:
-// Copyright (C) 2017-2023 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
///< Used while parsing content of a control-socket
CONTROL_SOCKET,
+ ///< Used while parsing content of a socket-type
+ CONTROL_SOCKET_TYPE,
+
+ ///< Used while parsing content of an authentication
+ AUTHENTICATION,
+
+ ///< Used while parsing content of an authentication type
+ AUTH_TYPE,
+
+ ///< Used while parsing content of a client
+ CLIENTS,
+
/// Used while parsing DhcpDdns/loggers structures.
LOGGERS,
"\"comment\": \"D2 config\" , "
"\"ip-address\" : \"192.168.1.33\" , "
"\"port\" : 88 , "
- "\"control-socket\": {"
- " \"comment\": \"Control channel\" , "
- " \"socket-type\": \"unix\" ,"
- " \"socket-name\": \"/tmp/d2-ctrl-channel\" "
+ "\"control-sockets\": ["
+ "{"
+ " \"socket-type\": \"unix\","
+ " \"socket-name\": \"/tmp/d2-ctrl-socket\","
+ " \"user-context\": { \"comment\":"
+ " \"Indirect comment\" }"
"},"
+ "{"
+ " \"comment\": \"HTTP control socket\","
+ " \"socket-type\": \"http\","
+ " \"socket-address\": \"::1\","
+ " \"socket-port\": 8053,"
+ " \"authentication\": {"
+ " \"comment\": \"basic HTTP authentication\","
+ " \"type\": \"basic\","
+ " \"clients\": [ {"
+ " \"comment\": \"admin is authorized\","
+ " \"user\": \"admin\","
+ " \"password\": \"1234\""
+ " } ]"
+ " }"
+ "}"
+ "],"
"\"tsig-keys\": ["
"{"
" \"user-context\": { "
ASSERT_TRUE(ctx->get("comment"));
EXPECT_EQ("\"D2 config\"", ctx->get("comment")->str());
- // Check control socket.
- ConstElementPtr ctrl_sock = d2_context->getControlSocketInfo();
- ASSERT_TRUE(ctrl_sock);
- ASSERT_TRUE(ctrl_sock->get("user-context"));
- EXPECT_EQ("{ \"comment\": \"Control channel\" }",
- ctrl_sock->get("user-context")->str());
+ // There is a UNIX control socket.
+ ConstElementPtr socket = d2_context->getControlSocketInfo();
+ ASSERT_TRUE(socket);
+ ConstElementPtr ctx_socket = socket->get("user-context");
+ ASSERT_TRUE(ctx_socket);
+ ASSERT_EQ(1, ctx_socket->size());
+ ASSERT_TRUE(ctx_socket->get("comment"));
+ EXPECT_EQ("\"Indirect comment\"", ctx_socket->get("comment")->str());
+
+ // There is a HTTP control socket with authentication.
+ socket = d2_context->getHttpControlSocketInfo();
+ ASSERT_TRUE(socket);
+ ctx_socket = socket->get("user-context");
+ ASSERT_TRUE(ctx_socket);
+ ASSERT_EQ(1, ctx_socket->size());
+ ASSERT_TRUE(ctx_socket->get("comment"));
+ EXPECT_EQ("\"HTTP control socket\"", ctx_socket->get("comment")->str());
+
+ // HTTP authentication.
+ ConstElementPtr auth = socket->get("authentication");
+ ASSERT_TRUE(auth);
+ ConstElementPtr ctx_auth = auth->get("user-context");
+ ASSERT_TRUE(ctx_auth);
+ ASSERT_EQ(1, ctx_auth->size());
+ ASSERT_TRUE(ctx_auth->get("comment"));
+ EXPECT_EQ("\"basic HTTP authentication\"", ctx_auth->get("comment")->str());
+
+ // Authentication client.
+ ConstElementPtr clients = auth->get("clients");
+ ASSERT_TRUE(clients);
+ ASSERT_EQ(1, clients->size());
+ ConstElementPtr client;
+ ASSERT_NO_THROW(client = clients->get(0));
+ ASSERT_TRUE(client);
+ ConstElementPtr ctx_client = client->get("user-context");
+ ASSERT_TRUE(ctx_client);
+ ASSERT_EQ(1, ctx_client->size());
+ ASSERT_TRUE(ctx_client->get("comment"));
+ EXPECT_EQ("\"admin is authorized\"", ctx_client->get("comment")->str());
// Check TSIG keys.
TSIGKeyInfoMapPtr keys = d2_context->getKeys();
-// Copyright (C) 2018-2023 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2018-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
EXPECT_EQ(1, status);
ASSERT_TRUE(txt);
ASSERT_EQ(Element::string, txt->getType());
- EXPECT_EQ("Mandatory 'socket-type' parameter missing", txt->stringValue());
- EXPECT_EQ(-1, CommandMgr::instance().getControlSocketFD());
-
- // bad type.
- string bad2 =
- "{"
- " \"ip-address\": \"192.168.77.1\","
- " \"port\": 777,"
- " \"control-socket\": {"
- " \"socket-type\": \"bogus\","
- " \"socket-name\": \"/tmp/d2.sock\""
- " },"
- " \"tsig-keys\": [],"
- " \"forward-ddns\" : {},"
- " \"reverse-ddns\" : {}"
- "}";
- ASSERT_NO_THROW(config = parseDHCPDDNS(bad2, true));
-
- answer = proc->configure(config, false);
- ASSERT_TRUE(answer);
-
- status = 0;
- txt = parseAnswer(status, answer);
- EXPECT_EQ(1, status);
- ASSERT_TRUE(txt);
- ASSERT_EQ(Element::string, txt->getType());
- EXPECT_EQ("Invalid 'socket-type' parameter value bogus",
+ EXPECT_EQ("'socket-type' parameter is mandatory in control-sockets items",
txt->stringValue());
EXPECT_EQ(-1, CommandMgr::instance().getControlSocketFD());
"name": "d2.md5.key",
"secret": "sensitivejdPJI5QxlpnfQ==",
},
- ]
+ ],
+ "control-sockets": [
+ {
+ "socket-type": "http",
+ "socket-address": "::1",
+ "authentication": {
+ "clients": [
+ {
+ "password-file": "/tmp/pwd",
+ }
+ ],
+ "type": "basic",
+ },
+ "socket-port": 8053,
+ },
+ ],
},
})");
testParser(txt, D2ParserContext::PARSER_DHCPDDNS, false);
addLog("<string>:14.8");
addLog("<string>:22.45");
addLog("<string>:23.8");
- addLog("<string>:25.4");
+ addLog("<string>:32.42");
+ addLog("<string>:35.26");
+ addLog("<string>:37.28");
+ addLog("<string>:38.8");
+ addLog("<string>:39.6");
+ addLog("<string>:40.4");
EXPECT_TRUE(checkFile());
// Test with many consecutive commas.
{
"DhcpDdns": {
- "control-socket": {
- "socket-name": "/tmp/kea-ddns-ctrl-socket",
- "socket-type": "unix"
- },
+ "control-sockets": [
+ {
+ "socket-name": "/tmp/kea-ddns-ctrl-socket",
+ "socket-type": "unix"
+ }
+ ],
"dns-server-timeout": 1000,
"forward-ddns": {
"ddns-domains": [
" }"
" }"
" ],"
- " \"control-socket\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"/tmp/kea4-ctrl-socket\","
- " \"user-context\": { \"comment\": \"Indirect comment\" }"
- " },"
+ " \"control-sockets\": ["
+ " {"
+ " \"socket-type\": \"unix\","
+ " \"socket-name\": \"/tmp/kea4-ctrl-socket\","
+ " \"user-context\": { \"comment\": \"Indirect comment\" }"
+ " },"
+ " {"
+ " \"comment\": \"HTTP control socket\","
+ " \"socket-type\": \"http\","
+ " \"socket-address\": \"::1\","
+ " \"socket-port\": 8000,"
+ " \"authentication\": {"
+ " \"comment\": \"basic HTTP authentication\","
+ " \"type\": \"basic\","
+ " \"clients\": [ {"
+ " \"comment\": \"admin is authorized\","
+ " \"user\": \"admin\","
+ " \"password\": \"1234\""
+ " } ]"
+ " }"
+ " }"
+ " ],"
" \"shared-networks\": [ {"
" \"comment\": \"A shared network\","
" \"name\": \"foo\","
ASSERT_TRUE(ctx_class->get("version"));
EXPECT_EQ("1", ctx_class->get("version")->str());
- // There is a control socket.
+ // There is a UNIX control socket.
ConstElementPtr socket =
CfgMgr::instance().getStagingCfg()->getControlSocketInfo();
ASSERT_TRUE(socket);
ASSERT_TRUE(socket->get("socket-name"));
EXPECT_EQ("\"/tmp/kea4-ctrl-socket\"", socket->get("socket-name")->str());
- // Check control socket comment and user context.
+ // Check UNIX control socket comment and user context.
ConstElementPtr ctx_socket = socket->get("user-context");
+ ASSERT_TRUE(ctx_socket);
ASSERT_EQ(1, ctx_socket->size());
ASSERT_TRUE(ctx_socket->get("comment"));
EXPECT_EQ("\"Indirect comment\"", ctx_socket->get("comment")->str());
+ // There is a HTTP control socket with authentication.
+ socket = CfgMgr::instance().getStagingCfg()->getHttpControlSocketInfo();
+ ASSERT_TRUE(socket);
+ ASSERT_TRUE(socket->get("socket-type"));
+ EXPECT_EQ("\"http\"", socket->get("socket-type")->str());
+ ASSERT_TRUE(socket->get("socket-address"));
+ EXPECT_EQ("\"::1\"", socket->get("socket-address")->str());
+ ASSERT_TRUE(socket->get("socket-port"));
+ EXPECT_EQ("8000", socket->get("socket-port")->str());
+
+ // Check HTTP control socket comment.
+ ctx_socket = socket->get("user-context");
+ ASSERT_TRUE(ctx_socket);
+ ASSERT_EQ(1, ctx_socket->size());
+ ASSERT_TRUE(ctx_socket->get("comment"));
+ EXPECT_EQ("\"HTTP control socket\"", ctx_socket->get("comment")->str());
+
+ // HTTP authentication.
+ ConstElementPtr auth = socket->get("authentication");
+ ASSERT_TRUE(auth);
+ ASSERT_TRUE(auth->get("type"));
+ EXPECT_EQ("\"basic\"", auth->get("type")->str());
+ ConstElementPtr ctx_auth = auth->get("user-context");
+ ASSERT_TRUE(ctx_auth);
+ ASSERT_EQ(1, ctx_auth->size());
+ ASSERT_TRUE(ctx_auth->get("comment"));
+ EXPECT_EQ("\"basic HTTP authentication\"", ctx_auth->get("comment")->str());
+
+ // Authentication client.
+ ConstElementPtr clients = auth->get("clients");
+ ASSERT_TRUE(clients);
+ ASSERT_EQ(1, clients->size());
+ ConstElementPtr client;
+ ASSERT_NO_THROW(client = clients->get(0));
+ ASSERT_TRUE(client);
+ ASSERT_TRUE(client->get("user"));
+ ASSERT_EQ("\"admin\"", client->get("user")->str());
+ ASSERT_TRUE(client->get("password"));
+ ASSERT_EQ("\"1234\"", client->get("password")->str());
+ ConstElementPtr ctx_client = client->get("user-context");
+ ASSERT_TRUE(ctx_client);
+ ASSERT_EQ(1, ctx_client->size());
+ ASSERT_TRUE(ctx_client->get("comment"));
+ EXPECT_EQ("\"admin is authorized\"", ctx_client->get("comment")->str());
+
// Now verify that the shared network was indeed configured.
const CfgSharedNetworks4Ptr& cfg_net =
CfgMgr::instance().getStagingCfg()->getCfgSharedNetworks4();
" }\n"
" }\n"
" ],\n"
-" \"control-socket\": {\n"
-" \"socket-name\": \"/tmp/kea4-ctrl-socket\",\n"
-" \"socket-type\": \"unix\",\n"
-" \"user-context\": {\n"
-" \"comment\": \"Indirect comment\"\n"
+" \"control-sockets\": [\n"
+" {\n"
+" \"socket-name\": \"/tmp/kea4-ctrl-socket\",\n"
+" \"socket-type\": \"unix\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"Indirect comment\"\n"
+" }\n"
+" },\n"
+" {\n"
+" \"authentication\": {\n"
+" \"clients\": [\n"
+" {\n"
+" \"password\": \"1234\",\n"
+" \"user\": \"admin\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"admin is authorized\"\n"
+" }\n"
+" }\n"
+" ],\n"
+" \"type\": \"basic\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"basic HTTP authentication\"\n"
+" }\n"
+" },\n"
+" \"socket-address\": \"::1\",\n"
+" \"socket-port\": 8000,\n"
+" \"socket-type\": \"http\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"HTTP control socket\"\n"
+" }\n"
" }\n"
-" },\n"
+" ],\n"
" \"dhcp-ddns\": {\n"
" \"enable-updates\": false,\n"
" \"user-context\": {\n"
" \"user-context\": {\n"
" \"comment\": \"Indirect comment\"\n"
" }\n"
+" },\n"
+" {\n"
+" \"authentication\": {\n"
+" \"clients\": [\n"
+" {\n"
+" \"password\": \"1234\",\n"
+" \"user\": \"admin\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"admin is authorized\"\n"
+" }\n"
+" }\n"
+" ],\n"
+" \"type\": \"basic\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"basic HTTP authentication\"\n"
+" }\n"
+" },\n"
+" \"socket-address\": \"::1\",\n"
+" \"socket-port\": 8000,\n"
+" \"socket-type\": \"http\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"HTTP control socket\"\n"
+" }\n"
" }\n"
" ],\n"
" \"ddns-conflict-resolution-mode\": \"check-with-dhcid\",\n"
" }"
" }"
" ],"
- " \"control-socket\": {"
- " \"socket-type\": \"unix\","
- " \"socket-name\": \"/tmp/kea6-ctrl-socket\","
- " \"user-context\": { \"comment\": \"Indirect comment\" }"
- " },"
+ " \"control-sockets\": ["
+ " {"
+ " \"socket-type\": \"unix\","
+ " \"socket-name\": \"/tmp/kea6-ctrl-socket\","
+ " \"user-context\": { \"comment\": \"Indirect comment\" }"
+ " },"
+ " {"
+ " \"comment\": \"HTTP control socket\","
+ " \"socket-type\": \"http\","
+ " \"socket-address\": \"127.0.0.1\","
+ " \"socket-port\": 8000,"
+ " \"authentication\": {"
+ " \"comment\": \"basic HTTP authentication\","
+ " \"type\": \"basic\","
+ " \"clients\": [ {"
+ " \"comment\": \"admin is authorized\","
+ " \"user\": \"admin\","
+ " \"password\": \"1234\""
+ " } ]"
+ " }"
+ " }"
+ " ],"
" \"shared-networks\": [ {"
" \"comment\": \"A shared network\","
" \"name\": \"foo\","
ASSERT_TRUE(ctx_class->get("version"));
EXPECT_EQ("1", ctx_class->get("version")->str());
- // There is a control socket.
+ // There is a UNIX control socket.
ConstElementPtr socket =
CfgMgr::instance().getStagingCfg()->getControlSocketInfo();
ASSERT_TRUE(socket);
ASSERT_TRUE(socket->get("socket-name"));
EXPECT_EQ("\"/tmp/kea6-ctrl-socket\"", socket->get("socket-name")->str());
- // Check control socket comment and user context.
+ // Check UNIX control socket comment and user context.
ConstElementPtr ctx_socket = socket->get("user-context");
+ ASSERT_TRUE(ctx_socket);
ASSERT_EQ(1, ctx_socket->size());
ASSERT_TRUE(ctx_socket->get("comment"));
EXPECT_EQ("\"Indirect comment\"", ctx_socket->get("comment")->str());
+ // There is a HTTP control socket with authentication.
+ socket = CfgMgr::instance().getStagingCfg()->getHttpControlSocketInfo();
+ ASSERT_TRUE(socket);
+ ASSERT_TRUE(socket->get("socket-type"));
+ EXPECT_EQ("\"http\"", socket->get("socket-type")->str());
+ ASSERT_TRUE(socket->get("socket-address"));
+ EXPECT_EQ("\"127.0.0.1\"", socket->get("socket-address")->str());
+ ASSERT_TRUE(socket->get("socket-port"));
+ EXPECT_EQ("8000", socket->get("socket-port")->str());
+
+ // Check HTTP control socket comment.
+ ctx_socket = socket->get("user-context");
+ ASSERT_TRUE(ctx_socket);
+ ASSERT_EQ(1, ctx_socket->size());
+ ASSERT_TRUE(ctx_socket->get("comment"));
+ EXPECT_EQ("\"HTTP control socket\"", ctx_socket->get("comment")->str());
+
+ // HTTP authentication.
+ ConstElementPtr auth = socket->get("authentication");
+ ASSERT_TRUE(auth);
+ ASSERT_TRUE(auth->get("type"));
+ EXPECT_EQ("\"basic\"", auth->get("type")->str());
+ ConstElementPtr ctx_auth = auth->get("user-context");
+ ASSERT_TRUE(ctx_auth);
+ ASSERT_EQ(1, ctx_auth->size());
+ ASSERT_TRUE(ctx_auth->get("comment"));
+ EXPECT_EQ("\"basic HTTP authentication\"", ctx_auth->get("comment")->str());
+
+ // Authentication client.
+ ConstElementPtr clients = auth->get("clients");
+ ASSERT_TRUE(clients);
+ ASSERT_EQ(1, clients->size());
+ ConstElementPtr client;
+ ASSERT_NO_THROW(client = clients->get(0));
+ ASSERT_TRUE(client);
+ ASSERT_TRUE(client->get("user"));
+ ASSERT_EQ("\"admin\"", client->get("user")->str());
+ ASSERT_TRUE(client->get("password"));
+ ASSERT_EQ("\"1234\"", client->get("password")->str());
+ ConstElementPtr ctx_client = client->get("user-context");
+ ASSERT_TRUE(ctx_client);
+ ASSERT_EQ(1, ctx_client->size());
+ ASSERT_TRUE(ctx_client->get("comment"));
+ EXPECT_EQ("\"admin is authorized\"", ctx_client->get("comment")->str());
+
// Now verify that the shared network was indeed configured.
const CfgSharedNetworks6Ptr& cfg_net =
CfgMgr::instance().getStagingCfg()->getCfgSharedNetworks6();
" }\n"
" }\n"
" ],\n"
-" \"control-socket\": {\n"
-" \"socket-name\": \"/tmp/kea6-ctrl-socket\",\n"
-" \"socket-type\": \"unix\",\n"
-" \"user-context\": {\n"
-" \"comment\": \"Indirect comment\"\n"
+" \"control-sockets\": [\n"
+" {\n"
+" \"socket-name\": \"/tmp/kea6-ctrl-socket\",\n"
+" \"socket-type\": \"unix\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"Indirect comment\"\n"
+" }\n"
+" },\n"
+" {\n"
+" \"authentication\": {\n"
+" \"clients\": [\n"
+" {\n"
+" \"password\": \"1234\",\n"
+" \"user\": \"admin\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"admin is authorized\"\n"
+" }\n"
+" }\n"
+" ],\n"
+" \"type\": \"basic\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"basic HTTP authentication\"\n"
+" }\n"
+" },\n"
+" \"socket-address\": \"127.0.0.1\",\n"
+" \"socket-port\": 8000,\n"
+" \"socket-type\": \"http\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"HTTP control socket\"\n"
+" }\n"
" }\n"
-" },\n"
+" ],\n"
" \"dhcp-ddns\": {\n"
" \"enable-updates\": false,\n"
" \"user-context\": {\n"
" \"user-context\": {\n"
" \"comment\": \"Indirect comment\"\n"
" }\n"
+" },\n"
+" {\n"
+" \"authentication\": {\n"
+" \"clients\": [\n"
+" {\n"
+" \"password\": \"1234\",\n"
+" \"user\": \"admin\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"admin is authorized\"\n"
+" }\n"
+" }\n"
+" ],\n"
+" \"type\": \"basic\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"basic HTTP authentication\"\n"
+" }\n"
+" },\n"
+" \"socket-address\": \"127.0.0.1\",\n"
+" \"socket-port\": 8000,\n"
+" \"socket-type\": \"http\",\n"
+" \"user-context\": {\n"
+" \"comment\": \"HTTP control socket\"\n"
+" }\n"
" }\n"
" ],\n"
" \"ddns-conflict-resolution-mode\": \"check-with-dhcid\",\n"
forward_mgr_(new DdnsDomainListMgr("forward-ddns")),
reverse_mgr_(new DdnsDomainListMgr("reverse-ddns")),
keys_(new TSIGKeyInfoMap()),
- control_socket_(ConstElementPtr()) {
+ unix_control_socket_(ConstElementPtr()),
+ http_control_socket_(ConstElementPtr()) {
}
D2CfgContext::D2CfgContext(const D2CfgContext& rhs) : ConfigBase(rhs) {
keys_ = rhs.keys_;
- control_socket_ = rhs.control_socket_;
+ unix_control_socket_ = rhs.unix_control_socket_;
+
+ http_control_socket_ = rhs.http_control_socket_;
hooks_config_ = rhs.hooks_config_;
}
tsig_keys->add(key.second->toElement());
}
d2->set("tsig-keys", tsig_keys);
- // Set control-socket (skip if null as empty is not legal)
- if (!isNull(control_socket_)) {
- d2->set("control-socket", UserContext::toElement(control_socket_));
+ // Set control-sockets.
+ ElementPtr control_sockets = Element::createList();
+ if (!isNull(unix_control_socket_)) {
+ control_sockets->add(UserContext::toElement(unix_control_socket_));
+ }
+ if (!isNull(http_control_socket_)) {
+ control_sockets->add(UserContext::toElement(http_control_socket_));
+ }
+ if (!control_sockets->empty()) {
+ d2->set("control-sockets", control_sockets);
}
// Set hooks-libraries
d2->set("hooks-libraries", hooks_config_.toElement());
return (getD2CfgContext()->getControlSocketInfo());
}
+const isc::data::ConstElementPtr
+D2CfgMgr::getHttpControlSocketInfo() {
+ return (getD2CfgContext()->getHttpControlSocketInfo());
+}
+
std::string
D2CfgMgr::getConfigSummary(const uint32_t) {
return (getD2Params()->getConfigSummary());
keys_ = keys;
}
- /// @brief Returns information about control socket
+ /// @brief Returns information about UNIX control socket
/// @return pointer to the Element that holds control-socket map
const isc::data::ConstElementPtr getControlSocketInfo() const {
- return (control_socket_);
+ return (unix_control_socket_);
}
- /// @brief Sets information about the control socket
+ /// @brief Sets information about the UNIX control socket
/// @param control_socket Element that holds control-socket map
void setControlSocketInfo(const isc::data::ConstElementPtr& control_socket) {
- control_socket_ = control_socket;
+ unix_control_socket_ = control_socket;
+ }
+
+ /// @brief Returns information about HTTP/HTTPS control socket
+ /// @return pointer to the Element that holds control-socket map
+ const isc::data::ConstElementPtr getHttpControlSocketInfo() const {
+ return (http_control_socket_);
+ }
+
+ /// @brief Sets information about the HTTP/HTTPS control socket
+ /// @param control_socket Element that holds control-socket map
+ void setHttpControlSocketInfo(const isc::data::ConstElementPtr& control_socket) {
+ http_control_socket_ = control_socket;
}
/// @brief Returns non-const reference to configured hooks libraries.
/// @brief Storage for the map of TSIGKeyInfos.
TSIGKeyInfoMapPtr keys_;
- /// @brief Pointer to the control-socket information.
- isc::data::ConstElementPtr control_socket_;
+ /// @brief Pointer to the UNIX control-socket information.
+ isc::data::ConstElementPtr unix_control_socket_;
+
+ /// @brief Pointer to the HTTP/HTTPS control-socket information.
+ isc::data::ConstElementPtr http_control_socket_;
/// @brief Configured hooks libraries.
isc::hooks::HooksConfig hooks_config_;
/// @return reference to const D2ParamsPtr
const D2ParamsPtr& getD2Params();
- /// @brief Convenience method fetches information about control socket
- /// from context
+ /// @brief Convenience method fetches information about
+ /// UNIX control socket from context
/// @return pointer to the Element that holds control-socket map
const isc::data::ConstElementPtr getControlSocketInfo();
+ /// @brief Convenience method fetches information about
+ /// HTTP/HTTPS control socket from context
+ /// @return pointer to the Element that holds control-socket map
+ const isc::data::ConstElementPtr getHttpControlSocketInfo();
+
/// @brief Returns configuration summary in the textual format.
///
/// @param selection Bitfield which describes the parts of the configuration
/// "interface" : "eth1" ,
/// "ip-address" : "192.168.1.33" ,
/// "port" : 88 ,
-/// "control-socket":
-/// {
-/// "socket-type": "unix" ,
-/// "socket-name": "/tmp/kea-ddns-ctrl-socket"
-//// },
+/// "control-sockets":
+/// [
+/// {
+/// "socket-type": "unix" ,
+/// "socket-name": "/tmp/kea-ddns-ctrl-socket"
+/// }
+/// ],
/// "tsig-keys":
//// [
/// {
ctx->setContext(user);
}
- ConstElementPtr socket = config->get("control-socket");
- if (socket) {
- if (socket->getType() != Element::map) {
- isc_throw(D2CfgError, "Specified control-socket is expected to be a map"
- ", i.e. a structure defined within { }");
+ // Get control sockets.
+ ConstElementPtr control_sockets = config->get("control-sockets");
+ ConstElementPtr control_socket = config->get("control-socket");
+ if (control_socket) {
+ ElementPtr l = Element::createList();
+ l->add(UserContext::toElement(control_socket));
+ control_sockets = l;
+ }
+ if (control_sockets) {
+ if (control_sockets->getType() != Element::list) {
+ // Sanity check: not supposed to fail.
+ isc_throw(D2CfgError,
+ "Specified control-sockets is expected to be a list");
+ }
+ bool seen_unix(false);
+ bool seen_http(false);
+ for (ConstElementPtr socket : control_sockets->listValue()) {
+ if (socket->getType() != Element::map) {
+ // Sanity check: not supposed to fail.
+ isc_throw(D2CfgError,
+ "Specified control-sockets is expected to be a list of maps");
+ }
+ ConstElementPtr socket_type = socket->get("socket-type");
+ if (!socket_type) {
+ isc_throw(D2CfgError,
+ "'socket-type' parameter is mandatory in control-sockets items");
+ }
+ if (socket_type->getType() != Element::string) {
+ // Sanity check: not supposed to fail.
+ isc_throw(D2CfgError,
+ "'socket-type' parameter is expected to be a string");
+ }
+ std::string type = socket_type->stringValue();
+ if (type == "unix") {
+ if (seen_unix) {
+ isc_throw(D2CfgError,
+ "control socket of type 'unix' already configured");
+ }
+ seen_unix = true;
+ ctx->setControlSocketInfo(socket);
+ } else if ((type == "http") || (type == "https")) {
+ if (seen_http) {
+ isc_throw(D2CfgError,
+ "control socket of type 'http' or 'https'"
+ " already configured");
+ }
+ seen_http = true;
+ ctx->setHttpControlSocketInfo(socket);
+ } else {
+ // Sanity check: not supposed to fail.
+ isc_throw(D2CfgError,
+ "unsupported 'socket-type': '" << type
+ << "' not 'unix', 'http' or 'https'");
+ }
}
- ctx->setControlSocketInfo(socket);
}
// Finally, let's get the hook libs!