]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3477] Checkpoint before regen
authorFrancis Dupont <fdupont@isc.org>
Thu, 4 Jul 2024 12:18:01 +0000 (14:18 +0200)
committerFrancis Dupont <fdupont@isc.org>
Thu, 1 Aug 2024 07:23:53 +0000 (09:23 +0200)
doc/examples/kea6/all-keys.json
doc/examples/kea6/comments.json
src/bin/dhcp4/dhcp4_parser.yy
src/bin/dhcp6/dhcp6_lexer.ll
src/bin/dhcp6/dhcp6_parser.yy
src/bin/dhcp6/json_config_parser.cc
src/bin/dhcp6/parser_context.cc
src/bin/dhcp6/parser_context.h
src/bin/dhcp6/tests/parser_unittest.cc
src/lib/dhcpsrv/parsers/simple_parser6.cc

index 9ccbfc2d84c3e7bf6b66b4a0f10f302c3ab8f59f..5fbea90be476f1b05ccf5334e3f6ddd2bfd05f41 100644 (file)
             "lenient-option-parsing": true
         },
 
-        // Command control socket configuration parameters for the Kea DHCPv6 server.
-        "control-socket": {
-            // Location of the UNIX domain socket file the DHCPv6 server uses
-            // to receive control commands from the Kea Control Agent or the
-            // local server administrator.
-            "socket-name": "/tmp/kea6-ctrl-socket",
-
-            // Control socket type used by the Kea DHCPv6 server. The 'unix'
-            // socket is currently the only supported type.
-            "socket-type": "unix"
-        },
+        // Command control socket configuration parameters for the Kea DHCPv4 server.
+        "control-sockets": [
+            {
+                // Control socket type used by the Kea DHCPv4 server.
+                // Must be unix, http or https.
+                "socket-type": "unix",
+
+               // Location of the UNIX domain socket file the DHCPv4
+               // server uses to receive control commands from the
+               // local server administrator.
+               "socket-name": "/tmp/kea4-ctrl-socket"
+            },
+            {
+                // Control socket type used by the Kea DHCPv4 server.
+                // Must be unix, http or https.
+                "socket-type": "https",
+
+                // Address of the HTTPS socket the Kea DHCPv4 server should
+                // listen for incoming queries. In fact an alias of
+                // socket-name.
+                "socket-address": "::1",
+
+                // Port of the HTTPS socket the Kea DHCPv4 server
+                // should listen for incoming queries. If enabling HA
+                // and multi-threading, the 8000 port is used by the
+                // HA hook library http listener. When using HA hook
+                // library with multi-threading to function, make sure
+                // the port used by dedicated listener is different
+                // (e.g. 8001) than the one specified here.  Note the
+                // commands should still be sent to a control socket.
+                // The dedicated listener is specifically for HA
+                // updates only.
+                "socket-port": 8000,
+
+                // TLS trust anchor (Certificate Authority). This is a
+                // file name or a directory path. Make sense with other
+                // TLS parameters only for the https control socket type.
+                "trust-anchor": "my-ca",
+
+                // TLS server certificate file name.
+                "cert-file": "my-cert",
+
+                // TLS server private key file name.
+                "key-file": "my-key",
+
+                // TLS require client certificates flag. Default is
+                // true and means require client certificates. False
+                // means they are optional.
+                "cert-required": true,
+
+                // Optional authentication.
+                "authentication": {
+
+                    // Required authentication type. The only
+                    // supported value is basic for the basic HTTP
+                    // authentication.
+                    "type": "basic",
+
+                    // An optional parameter is the basic HTTP
+                    // authentication realm.  Its default is
+                    // "kea-dhcpv4-server"
+                    "realm": "kea-dhcpv4-server",
+
+                    // This optional parameter can be used to specify a common
+                    // prefix for files handling client credentials.
+                    "directory": "/tmp/kea-creds",
+
+                    // This list specifies the user ids and passwords
+                    // to use for basic HTTP authentication. If empty
+                    // or not present any client is authorized.
+                    "clients": [
+                        // This specifies an authorized client.
+                        {
+                            // The user id must not be empty or
+                            // contain the ':' character. It is a
+                            // mandatory parameter.
+                            "user": "admin",
+
+                            // If password is not specified an empty
+                            // password is used.
+                            "password": "1234"
+                        },
+
+                        // This specifies a hidden client.
+                        {
+                            // The user id is the content of the
+                            // file /tmp/kea-creds/hiddenu.
+                            "user-file": "hiddenu",
+
+                            // The password is the content of the
+                            // file /tmp/kea-creds/hiddenp.
+                            "password-file": "hiddenp"
+                        },
+
+                        // This specifies a hidden client using a
+                        // secret in a file.
+                        {
+                            // The secret is the content of the file
+                            // /tmp/kea-creds/hiddens which must be in
+                            // the <user-id>:<password> format.
+                            "password-file": "hiddens"
+                        }
+                    ]
+                }
+            }
+        ],
+
 
         // Specifies a prefix to be prepended to the generated Client FQDN.
         // It may be specified at the global, shared-network, and subnet levels.
index 88cdd413762ac9d04f55616781cd433924b37f9d..dbc48072ee9eeb20a0388645d8699b9f21237fed 100644 (file)
        }
    ],
 
-   // In control socket (more for the agent)
-   "control-socket": {
-       "socket-type": "unix",
-       "socket-name": "/tmp/kea6-ctrl-socket",
-       "user-context": { "comment": "Indirect comment" }
-   },
+   // In control sockets (more for the agent)
+   "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": "127.0.0.1",
+           "socket-port": 8000,
+           
+           // In authentication
+           "authentication": {
+               "comment": "basic HTTP authentication",
+               "type": "basic",
+               // In basic HTTP authentication clients
+               "clients": [ {
+                   "comment": "admin is authorized",
+                   "user": "admin",
+                   "password": "1234"
+               } ]
+           }
+       }
+   ],
 
    // In shared networks
    "shared-networks": [ {
index a2704c6ed4973fb9020369a297907e34919196e8..d41c568694e3cd4eb7ceb0b0905ef696a1ca607a 100644 (file)
@@ -2513,6 +2513,7 @@ dhcp4o6_port: DHCP4O6_PORT COLON INTEGER {
 
 control_socket: CONTROL_SOCKET {
     ctx.unique("control-socket", ctx.loc2pos(@1));
+    ctx.unique("control-sockets", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("control-socket", m);
     ctx.stack_.push_back(m);
@@ -2524,6 +2525,7 @@ control_socket: CONTROL_SOCKET {
 
 control_sockets: CONTROL_SOCKETS {
     ctx.unique("control-sockets", ctx.loc2pos(@1));
+    ctx.unique("control-socket", ctx.loc2pos(@1));
     ElementPtr l(new ListElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("control-sockets", l);
     ctx.stack_.push_back(l);
index 6c13cdfb52c059a568fadd10ab729a25565bb029..de968210fcd9f5ebb96ad7fc58f8375000642403 100644 (file)
@@ -551,6 +551,7 @@ ControlCharacterFill            [^"\\]|\\["\\/bfnrtu]
     case isc::dhcp::Parser6Context::OPTION_DEF:
     case isc::dhcp::Parser6Context::SERVER_ID:
     case isc::dhcp::Parser6Context::CONFIG_DATABASE:
+    case isc::dhcp::Parser6Context::AUTHENTICATION:
         return isc::dhcp::Dhcp6Parser::make_TYPE(driver.loc_);
     default:
         return isc::dhcp::Dhcp6Parser::make_STRING("type", driver.loc_);
@@ -589,6 +590,7 @@ ControlCharacterFill            [^"\\]|\\["\\/bfnrtu]
     case isc::dhcp::Parser6Context::LEASE_DATABASE:
     case isc::dhcp::Parser6Context::HOSTS_DATABASE:
     case isc::dhcp::Parser6Context::CONFIG_DATABASE:
+    case isc::dhcp::Parser6Context::CLIENTS:
         return isc::dhcp::Dhcp6Parser::make_USER(driver.loc_);
     default:
         return isc::dhcp::Dhcp6Parser::make_STRING("user", driver.loc_);
@@ -600,6 +602,7 @@ ControlCharacterFill            [^"\\]|\\["\\/bfnrtu]
     case isc::dhcp::Parser6Context::LEASE_DATABASE:
     case isc::dhcp::Parser6Context::HOSTS_DATABASE:
     case isc::dhcp::Parser6Context::CONFIG_DATABASE:
+    case isc::dhcp::Parser6Context::CLIENTS:
         return isc::dhcp::Dhcp6Parser::make_PASSWORD(driver.loc_);
     default:
         return isc::dhcp::Dhcp6Parser::make_STRING("password", driver.loc_);
@@ -780,6 +783,7 @@ ControlCharacterFill            [^"\\]|\\["\\/bfnrtu]
     case isc::dhcp::Parser6Context::LEASE_DATABASE:
     case isc::dhcp::Parser6Context::HOSTS_DATABASE:
     case isc::dhcp::Parser6Context::CONFIG_DATABASE:
+    case isc::dhcp::Parser6Context::CONTROL_SOCKET:
         return isc::dhcp::Dhcp6Parser::make_TRUST_ANCHOR(driver.loc_);
     default:
         return isc::dhcp::Dhcp6Parser::make_STRING("trust-anchor", driver.loc_);
@@ -791,6 +795,7 @@ ControlCharacterFill            [^"\\]|\\["\\/bfnrtu]
     case isc::dhcp::Parser6Context::LEASE_DATABASE:
     case isc::dhcp::Parser6Context::HOSTS_DATABASE:
     case isc::dhcp::Parser6Context::CONFIG_DATABASE:
+    case isc::dhcp::Parser6Context::CONTROL_SOCKET:
         return isc::dhcp::Dhcp6Parser::make_CERT_FILE(driver.loc_);
     default:
         return isc::dhcp::Dhcp6Parser::make_STRING("cert-file", driver.loc_);
@@ -802,6 +807,7 @@ ControlCharacterFill            [^"\\]|\\["\\/bfnrtu]
     case isc::dhcp::Parser6Context::LEASE_DATABASE:
     case isc::dhcp::Parser6Context::HOSTS_DATABASE:
     case isc::dhcp::Parser6Context::CONFIG_DATABASE:
+    case isc::dhcp::Parser6Context::CONTROL_SOCKET:
         return isc::dhcp::Dhcp6Parser::make_KEY_FILE(driver.loc_);
     default:
         return isc::dhcp::Dhcp6Parser::make_STRING("key-file", driver.loc_);
@@ -1322,6 +1328,8 @@ ControlCharacterFill            [^"\\]|\\["\\/bfnrtu]
     case isc::dhcp::Parser6Context::CLIENT_CLASSES:
     case isc::dhcp::Parser6Context::SERVER_ID:
     case isc::dhcp::Parser6Context::CONTROL_SOCKET:
+    case isc::dhcp::Parser6Context::AUTHENTICATION:
+    case isc::dhcp::Parser6Context::CLIENTS:
     case isc::dhcp::Parser6Context::DHCP_QUEUE_CONTROL:
     case isc::dhcp::Parser6Context::DHCP_MULTI_THREADING:
     case isc::dhcp::Parser6Context::LOGGERS:
@@ -1346,6 +1354,8 @@ ControlCharacterFill            [^"\\]|\\["\\/bfnrtu]
     case isc::dhcp::Parser6Context::CLIENT_CLASSES:
     case isc::dhcp::Parser6Context::SERVER_ID:
     case isc::dhcp::Parser6Context::CONTROL_SOCKET:
+    case isc::dhcp::Parser6Context::AUTHENTICATION:
+    case isc::dhcp::Parser6Context::CLIENTS:
     case isc::dhcp::Parser6Context::DHCP_QUEUE_CONTROL:
     case isc::dhcp::Parser6Context::DHCP_MULTI_THREADING:
     case isc::dhcp::Parser6Context::LOGGERS:
@@ -2022,6 +2032,15 @@ ControlCharacterFill            [^"\\]|\\["\\/bfnrtu]
     }
 }
 
+\"control-sockets\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::DHCP6:
+        return isc::dhcp::Dhcp6Parser::make_CONTROL_SOCKETS(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("control-sockets", driver.loc_);
+    }
+}
+
 \"socket-type\" {
     switch(driver.ctx_) {
     case isc::dhcp::Parser6Context::CONTROL_SOCKET:
@@ -2031,6 +2050,33 @@ ControlCharacterFill            [^"\\]|\\["\\/bfnrtu]
     }
 }
 
+\"unix\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::CONTROL_SOCKET_TYPE:
+        return isc::dhcp::Dhcp6Parser::make_UNIX(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("unix", driver.loc_);
+    }
+}
+
+\"http\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::CONTROL_SOCKET_TYPE:
+        return isc::dhcp::Dhcp6Parser::make_HTTP(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("http", driver.loc_);
+    }
+}
+
+\"https\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::CONTROL_SOCKET_TYPE:
+        return isc::dhcp::Dhcp6Parser::make_HTTPS(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("https", driver.loc_);
+    }
+}
+
 \"socket-name\" {
     switch(driver.ctx_) {
     case isc::dhcp::Parser6Context::CONTROL_SOCKET:
@@ -2040,6 +2086,96 @@ ControlCharacterFill            [^"\\]|\\["\\/bfnrtu]
     }
 }
 
+\"socket-address\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::CONTROL_SOCKET:
+        return isc::dhcp::Dhcp6Parser::make_SOCKET_ADDRESS(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("socket-address", driver.loc_);
+    }
+}
+
+\"socket-port\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::CONTROL_SOCKET:
+        return isc::dhcp::Dhcp6Parser::make_SOCKET_PORT(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("socket-port", driver.loc_);
+    }
+}
+
+\"authentication\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::CONTROL_SOCKET:
+        return isc::dhcp::Dhcp6Parser::make_AUTHENTICATION(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("authentication", driver.loc_);
+    }
+}
+
+\"basic\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::AUTH_TYPE:
+        return isc::dhcp::Dhcp6Parser::make_BASIC(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("basic", driver.loc_);
+    }
+}
+
+\"realm\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::AUTHENTICATION:
+        return isc::dhcp::Dhcp6Parser::make_REALM(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("realm", driver.loc_);
+    }
+}
+
+\"directory\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::AUTHENTICATION:
+        return isc::dhcp::Dhcp6Parser::make_DIRECTORY(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("directory", driver.loc_);
+    }
+}
+
+\"clients\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::AUTHENTICATION:
+        return isc::dhcp::Dhcp6Parser::make_CLIENTS(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("clients", driver.loc_);
+    }
+}
+
+\"user-file\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::CLIENTS:
+        return isc::dhcp::Dhcp6Parser::make_USER_FILE(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("user-file", driver.loc_);
+    }
+}
+
+\"password-file\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::CLIENTS:
+        return isc::dhcp::Dhcp6Parser::make_PASSWORD_FILE(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("password-file", driver.loc_);
+    }
+}
+
+\"cert-required\" {
+    switch(driver.ctx_) {
+    case isc::dhcp::Parser6Context::CONTROL_SOCKET:
+        return isc::dhcp::Dhcp6Parser::make_CERT_REQUIRED(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp6Parser::make_STRING("cert-required", driver.loc_);
+    }
+}
+
 \"dhcp-queue-control\" {
     switch(driver.ctx_) {
     case isc::dhcp::Parser6Context::DHCP6:
index 834dfbca25c5767990aac909b510a322a4c94e36..e40345ad94a7f6b0bf96e6036ecfa7537bf77eb1 100644 (file)
@@ -225,8 +225,23 @@ using namespace std;
   PACKET_QUEUE_SIZE "packet-queue-size"
 
   CONTROL_SOCKET "control-socket"
+  CONTROL_SOCKETS "control-sockets"
   SOCKET_TYPE "socket-type"
   SOCKET_NAME "socket-name"
+  UNIX "unix"
+  HTTP "http"
+  HTTPS "https"
+  SOCKET_NAME "socket-name"
+  SOCKET_ADDRESS "socket-address"
+  SOCKET_PORT "socket-port"
+  AUTHENTICATION "authentication"
+  BASIC "basic"
+  REALM "realm"
+  DIRECTORY "directory"
+  CLIENTS "clients"
+  USER_FILE "user-file"
+  PASSWORD_FILE "password-file"
+  CERT_REQUIRED "cert-required"
 
   DHCP_QUEUE_CONTROL "dhcp-queue-control"
   ENABLE_QUEUE "enable-queue"
@@ -299,6 +314,8 @@ using namespace std;
 %type <ElementPtr> ncr_protocol_value
 %type <ElementPtr> ddns_replace_client_name_value
 %type <ElementPtr> ddns_conflict_resolution_mode_value
+%type <ElementPtr> control_socket_type_value
+%type <ElementPtr> auth_type_value
 
 %printer { yyoutput << $$; } <*>;
 
@@ -524,6 +541,7 @@ global_param: data_directory
             | server_id
             | dhcp4o6_port
             | control_socket
+            | control_sockets
             | dhcp_queue_control
             | dhcp_ddns
             | user_context
@@ -2625,6 +2643,7 @@ dhcp4o6_port: DHCP4O6_PORT COLON INTEGER {
 
 control_socket: CONTROL_SOCKET {
     ctx.unique("control-socket", ctx.loc2pos(@1));
+    ctx.unique("control-sockets", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("control-socket", m);
     ctx.stack_.push_back(m);
@@ -2634,6 +2653,37 @@ control_socket: CONTROL_SOCKET {
     ctx.leave();
 };
 
+control_sockets: CONTROL_SOCKETS {
+    ctx.unique("control-sockets", ctx.loc2pos(@1));
+    ctx.unique("control-socket", ctx.loc2pos(@1));
+    ElementPtr l(new ListElement(ctx.loc2pos(@1)));
+    ctx.stack_.back()->set("control-sockets", l);
+    ctx.stack_.push_back(l);
+    ctx.enter(ctx.CONTROL_SOCKET);
+} COLON LSQUARE_BRACKET control_socket_list RSQUARE_BRACKET {
+    ctx.stack_.pop_back();
+    ctx.leave();
+};
+
+control_socket_list: %empty
+                   | not_empty_control_socket_list
+                   ;
+
+not_empty_control_socket_list: control_socket_entry
+                             | not_empty_control_socket_list COMMA control_socket_entry
+                             | not_empty_control_socket_list COMMA {
+                                 ctx.warnAboutExtraCommas(@2);
+                                 }
+                             ;
+
+control_socket_entry: LCURLY_BRACKET {
+    ElementPtr m(new MapElement(ctx.loc2pos(@1)));
+    ctx.stack_.back()->add(m);
+    ctx.stack_.push_back(m);
+} control_socket_params RCURLY_BRACKET {
+    ctx.stack_.pop_back();
+};
+
 control_socket_params: control_socket_param
                      | control_socket_params COMMA control_socket_param
                      | control_socket_params COMMA {
@@ -2641,23 +2691,35 @@ control_socket_params: control_socket_param
                          }
                      ;
 
-control_socket_param: socket_type
-                    | socket_name
+control_socket_param: control_socket_type
+                    | control_socket_name
+                    | control_socket_address
+                    | control_socket_port
+                    | authentication
+                    | trust_anchor
+                    | cert_file
+                    | key_file
+                    | cert_required
                     | user_context
                     | comment
                     | unknown_map_entry
                     ;
 
-socket_type: SOCKET_TYPE {
+control_socket_type: SOCKET_TYPE {
     ctx.unique("socket-type", ctx.loc2pos(@1));
-    ctx.enter(ctx.NO_KEYWORD);
-} COLON STRING {
-    ElementPtr stype(new StringElement($4, ctx.loc2pos(@4)));
-    ctx.stack_.back()->set("socket-type", stype);
+    ctx.enter(ctx.CONTROL_SOCKET_TYPE);
+} COLON control_socket_type_value {
+    ctx.stack_.back()->set("socket-type", $4);
     ctx.leave();
 };
 
-socket_name: SOCKET_NAME {
+control_socket_type_value:
+    UNIX { $$ = ElementPtr(new StringElement("unix", ctx.loc2pos(@1))); }
+  | HTTP { $$ = ElementPtr(new StringElement("http", ctx.loc2pos(@1))); }
+  | HTTPS { $$ = ElementPtr(new StringElement("https", ctx.loc2pos(@1))); }
+  ;
+
+control_socket_name: SOCKET_NAME {
     ctx.unique("socket-name", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
@@ -2666,6 +2728,150 @@ socket_name: SOCKET_NAME {
     ctx.leave();
 };
 
+control_socket_address: SOCKET_ADDRESS {
+    ctx.unique("socket-address", ctx.loc2pos(@1));
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+    ElementPtr address(new StringElement($4, ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("socket-address", address);
+    ctx.leave();
+};
+
+control_socket_port: SOCKET_PORT COLON INTEGER {
+    ctx.unique("socket-port", ctx.loc2pos(@1));
+    ElementPtr port(new IntElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("socket-port", port);
+};
+
+cert_required: CERT_REQUIRED COLON BOOLEAN {
+    ctx.unique("cert-required", ctx.loc2pos(@1));
+    ElementPtr req(new BoolElement($3, ctx.loc2pos(@3)));
+    ctx.stack_.back()->set("cert-required", req);
+};
+
+// --- authentication ---------------------------------------------
+
+authentication: AUTHENTICATION {
+    ctx.unique("authentication", ctx.loc2pos(@1));
+    ElementPtr m(new MapElement(ctx.loc2pos(@1)));
+    ctx.stack_.back()->set("authentication", m);
+    ctx.stack_.push_back(m);
+    ctx.enter(ctx.AUTHENTICATION);
+} COLON LCURLY_BRACKET auth_params RCURLY_BRACKET {
+    // The type parameter is required
+    ctx.require("type", ctx.loc2pos(@4), ctx.loc2pos(@6));
+    ctx.stack_.pop_back();
+    ctx.leave();
+};
+
+auth_params: auth_param
+           | auth_params COMMA auth_param
+           | auth_params COMMA {
+               ctx.warnAboutExtraCommas(@2);
+               }
+           ;
+
+auth_param: auth_type
+          | realm
+          | directory
+          | clients
+          | comment
+          | user_context
+          | unknown_map_entry
+          ;
+
+auth_type: TYPE {
+    ctx.unique("type", ctx.loc2pos(@1));
+    ctx.enter(ctx.AUTH_TYPE);
+} COLON auth_type_value {
+    ctx.stack_.back()->set("type", $4);
+    ctx.leave();
+};
+
+auth_type_value: BASIC { $$ = ElementPtr(new StringElement("basic", ctx.loc2pos(@1))); }
+               ;
+
+realm: REALM {
+    ctx.unique("realm", ctx.loc2pos(@1));
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+    ElementPtr realm(new StringElement($4, ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("realm", realm);
+    ctx.leave();
+};
+
+directory: DIRECTORY {
+    ctx.unique("directory", ctx.loc2pos(@1));
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+    ElementPtr directory(new StringElement($4, ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("directory", directory);
+    ctx.leave();
+};
+
+clients: CLIENTS {
+    ctx.unique("clients", ctx.loc2pos(@1));
+    ElementPtr l(new ListElement(ctx.loc2pos(@1)));
+    ctx.stack_.back()->set("clients", l);
+    ctx.stack_.push_back(l);
+    ctx.enter(ctx.CLIENTS);
+} COLON LSQUARE_BRACKET clients_list RSQUARE_BRACKET {
+    ctx.stack_.pop_back();
+    ctx.leave();
+};
+
+clients_list: %empty
+            | not_empty_clients_list
+            ;
+
+not_empty_clients_list: basic_auth
+                      | not_empty_clients_list COMMA basic_auth
+                      | not_empty_clients_list COMMA {
+                          ctx.warnAboutExtraCommas(@2);
+                          }
+                      ;
+
+basic_auth: LCURLY_BRACKET {
+    ElementPtr m(new MapElement(ctx.loc2pos(@1)));
+    ctx.stack_.back()->add(m);
+    ctx.stack_.push_back(m);
+} clients_params RCURLY_BRACKET {
+    ctx.stack_.pop_back();
+};
+
+clients_params: clients_param
+              | clients_params COMMA clients_param
+              | clients_params COMMA {
+                  ctx.warnAboutExtraCommas(@2);
+                  }
+              ;
+
+clients_param: user
+             | user_file
+             | password
+             | password_file
+             | user_context
+             | comment
+             | unknown_map_entry
+             ;
+
+user_file: USER_FILE {
+    ctx.unique("user-file", ctx.loc2pos(@1));
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+    ElementPtr user(new StringElement($4, ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("user-file", user);
+    ctx.leave();
+};
+
+password_file: PASSWORD_FILE {
+    ctx.unique("password-file", ctx.loc2pos(@1));
+    ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+    ElementPtr password(new StringElement($4, ctx.loc2pos(@4)));
+    ctx.stack_.back()->set("password-file", password);
+    ctx.leave();
+};
 
 // --- dhcp-queue-control ---------------------------------------------
 
index 671d69a802ebbb3180e16894fa2c5a40b14abe73..80d5f1f34cd5fc28f32a4ded2ed74082791e4d88 100644 (file)
@@ -712,6 +712,7 @@ processDhcp6Config(isc::data::ConstElementPtr config_set) {
                 (config_pair.first == "option-data") ||
                 (config_pair.first == "mac-sources") ||
                 (config_pair.first == "control-socket") ||
+                (config_pair.first == "control-sockets") ||
                 (config_pair.first == "multi-threading") ||
                 (config_pair.first == "dhcp-queue-control") ||
                 (config_pair.first == "host-reservation-identifiers") ||
index ebf7bef835f84d81ce21f247a3c350a0227d5e08..04124a35b500d38f1ec992d9c049d060887fa477 100644 (file)
@@ -186,6 +186,14 @@ Parser6Context::contextName() {
         return ("duid-type");
     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 DHCP_QUEUE_CONTROL:
         return ("dhcp-queue-control");
     case DHCP_MULTI_THREADING:
index c410ddda6a943ce0d274a3962e2d6d823f750d3a..2f6fbfed4c499d3c35a572e615d78bf2068e37cb 100644 (file)
@@ -296,6 +296,20 @@ public:
         /// Used while parsing Dhcp6/control-socket structures.
         CONTROL_SOCKET,
 
+        /// Used while parsing Dhcp6/control-socket/socket-type structures.
+        CONTROL_SOCKET_TYPE,
+
+        /// Used while parsing Dhcp6/control-socket/authentication structures.
+        AUTHENTICATION,
+
+        /// Used while parsing Dhcp6/control-socket/authentication/type
+        /// structures.
+        AUTH_TYPE,
+
+        /// Used while parsing Dhcp6/control-socket/authentication/clients
+        /// structures.
+        CLIENTS,
+
         /// Used while parsing Dhcp6/dhcp-queue-control structures.
         DHCP_QUEUE_CONTROL,
 
index 1ba44e123606678016e821348e914fa9a102be62..78091d32d6066250606a3b7ce5fb01883affdb7c 100644 (file)
@@ -910,10 +910,21 @@ public:
 TEST_F(TrailingCommasTest, tests) {
     string txt(R"({
   "Dhcp6": {
-    "control-socket": {
-      "socket-name": "/tmp/kea-dhcp6-ctrl.sock",
-      "socket-type": "unix",
-    },
+    "control-sockets": [
+      {
+        "socket-type": "http",
+        "socket-address": "::1",
+        "authentication": {
+          "clients": [
+            {
+              "password-file": "/tmp/pwd",
+            }
+          ],
+          "type": "basic",
+        },
+        "socket-port": 8000,
+      },
+    ],
     "hooks-libraries": [
       {
         "library": "/usr/local/lib/kea/hooks/libdhcp_dummy.so",
@@ -961,22 +972,25 @@ TEST_F(TrailingCommasTest, tests) {
 })");
     testParser(txt, Parser6Context::PARSER_DHCP6, false);
 
-    addLog("<string>:5.28");
-    addLog("<string>:9.63");
-    addLog("<string>:10.8");
-    addLog("<string>:14.15");
-    addLog("<string>:15.8");
-    addLog("<string>:20.24");
-    addLog("<string>:28.31");
-    addLog("<string>:29.12");
-    addLog("<string>:31.28");
-    addLog("<string>:32.8");
-    addLog("<string>:43.38");
-    addLog("<string>:44.12");
-    addLog("<string>:47.16");
-    addLog("<string>:48.8");
-    addLog("<string>:49.6");
-    addLog("<string>:50.4");
+    addLog("<string>:10.42");
+    addLog("<string>:13.26");
+    addLog("<string>:15.28");
+    addLog("<string>:16.8");
+    addLog("<string>:20.63");
+    addLog("<string>:21.8");
+    addLog("<string>:25.15");
+    addLog("<string>:26.8");
+    addLog("<string>:31.24");
+    addLog("<string>:39.31");
+    addLog("<string>:40.12");
+    addLog("<string>:42.28");
+    addLog("<string>:43.8");
+    addLog("<string>:54.37");
+    addLog("<string>:55.12");
+    addLog("<string>:58.16");
+    addLog("<string>:59.8");
+    addLog("<string>:60.6");
+    addLog("<string>:61.4");
     EXPECT_TRUE(checkFile());
 
     // Test with many consecutive commas.
index fd2eca8dee431324da9b7f03e682b011c70133e3..e5b0c079e07c40febb94c75850510a2d381a619c 100644 (file)
@@ -61,6 +61,7 @@ const SimpleKeywords SimpleParser6::GLOBAL6_PARAMETERS = {
     { "server-id",                        Element::map },
     { "dhcp4o6-port",                     Element::integer },
     { "control-socket",                   Element::map },
+    { "control-sockets",                  Element::list },
     { "dhcp-queue-control",               Element::map },
     { "dhcp-ddns",                        Element::map },
     { "user-context",                     Element::map },