Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ISC Open Source Projects
Kea
Commits
926a65fa
Commit
926a65fa
authored
Jun 21, 2011
by
Stephen Morris
Browse files
Merge branch 'master' into trac1022
parents
2d39d007
e9798fc8
Changes
21
Hide whitespace changes
Inline
Side-by-side
src/bin/xfrout/xfrout.py.in
View file @
926a65fa
...
...
@@ -559,7 +559,7 @@ class XfroutServer:
#self._log = None
self._listen_sock_file = UNIX_SOCKET_FILE
self._shutdown_event = threading.Event()
self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler
, None, True
)
self._config_data = self._cc.get_full_config()
self._cc.start()
self._cc.add_remote_config(AUTH_SPECFILE_LOCATION);
...
...
src/lib/acl/Makefile.am
View file @
926a65fa
SUBDIRS
=
tests
SUBDIRS
=
.
tests
EXTRA_DIST
=
check.h acl.h
AM_CPPFLAGS
=
-I
$(top_srcdir)
/src/lib
-I
$(top_builddir)
/src/lib
AM_CPPFLAGS
+=
$(BOOST_INCLUDES)
# TODO: Once we have some cc file we are able to compile, create the library.
# For now, we have only header files, not creating empty library.
AM_CXXFLAGS
=
$(B10_CXXFLAGS)
lib_LTLIBRARIES
=
libacl.la
libacl_la_SOURCES
=
check.h acl.h
libacl_la_SOURCES
+=
loader.h loader.cc
libacl_la_LIBADD
=
$(top_builddir)
/src/lib/exceptions/libexceptions.la
libacl_la_LIBADD
+=
$(top_builddir)
/src/lib/cc/libcc.la
CLEANFILES
=
*
.gcno
*
.gcda
src/lib/acl/loader.cc
0 → 100644
View file @
926a65fa
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include
"loader.h"
using
namespace
std
;
namespace
isc
{
namespace
acl
{
BasicAction
defaultActionLoader
(
data
::
ConstElementPtr
actionEl
)
{
try
{
const
string
action
(
actionEl
->
stringValue
());
if
(
action
==
"ACCEPT"
)
{
return
(
ACCEPT
);
}
else
if
(
action
==
"REJECT"
)
{
return
(
REJECT
);
}
else
if
(
action
==
"DROP"
)
{
return
(
DROP
);
}
else
{
throw
LoaderError
(
__FILE__
,
__LINE__
,
string
(
"Unknown action '"
+
action
+
"'"
).
c_str
(),
actionEl
);
}
}
catch
(
const
data
::
TypeError
&
)
{
throw
LoaderError
(
__FILE__
,
__LINE__
,
"Invalid element type for action, must be string"
,
actionEl
);
}
}
}
}
src/lib/acl/loader.h
0 → 100644
View file @
926a65fa
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef ACL_LOADER_H
#define ACL_LOADER_H
#include
"acl.h"
#include
<cc/data.h>
#include
<boost/function.hpp>
#include
<boost/shared_ptr.hpp>
#include
<map>
namespace
isc
{
namespace
acl
{
/**
* \brief Exception for bad ACL specifications.
*
* This will be thrown by the Loader if the ACL description is malformed
* in some way.
*
* It also can hold optional JSON element where was the error detected, so
* it can be examined.
*
* Checks may subclass this exception for similar errors if they see it fit.
*/
class
LoaderError
:
public
BadValue
{
private:
const
data
::
ConstElementPtr
element_
;
public:
/**
* \brief Constructor.
*
* Should be used with isc_throw if the fourth argument isn't used.
*
* \param file The file where the throw happened.
* \param line Similar as file, just for the line number.
* \param what Human readable description of what happened.
* \param element This might be passed to hold the JSON element where
* the error was detected.
*/
LoaderError
(
const
char
*
file
,
size_t
line
,
const
char
*
what
,
data
::
ConstElementPtr
element
=
data
::
ConstElementPtr
())
:
BadValue
(
file
,
line
,
what
),
element_
(
element
)
{}
~
LoaderError
()
throw
()
{}
/**
* \brief Get the element.
*
* This returns the element where the error was detected. Note that it
* might be NULL in some situations.
*/
const
data
::
ConstElementPtr
&
element
()
const
{
return
(
element_
);
}
};
/**
* \brief Loader of the default actions of ACLs.
*
* Declared outside the Loader class, as this one does not need to be
* templated. This will throw LoaderError if the parameter isn't string
* or if it doesn't contain one of the accepted values.
*
* \param action The JSON representation of the action. It must be a string
* and contain one of "ACCEPT", "REJECT" or "DENY".
* \note We could define different names or add aliases if needed.
*/
BasicAction
defaultActionLoader
(
data
::
ConstElementPtr
action
);
/**
* \brief Loader of ACLs.
*
* The goal of this class is to convert JSON description of an ACL to object
* of the ACL class (including the checks inside it).
*
* The class can be used to load the checks only. This is supposed to be used
* by compound checks to create the subexpressions.
*
* To allow any kind of checks to exist in the application, creators are
* registered for the names of the checks.
*
* An ACL definition looks like this:
* \verbatim
* [
* {
* "action": "ACCEPT",
* "match-type": <parameter>
* },
* {
* "action": "REJECT",
* "match-type": <parameter>
* "another-match-type": [<parameter1>, <parameter2>]
* },
* {
* "action": "DROP"
* }
* ]
* \endverbatim
*
* This is a list of elements. Each element must have an "action"
* entry/keyword. That one specifies which action is returned if this
* element matches (the value of the key is passed to the action loader
* (see the constructor). It may be any piece of JSON which the action
* loader expects.
*
* The rest of the element are matches. The left side is the name of the
* match type (for example match for source IP address or match for message
* size). The <parameter> is whatever is needed to describe the match and
* depends on the match type, the loader passes it verbatim to creator
* of that match type.
*
* There may be multiple match types in single element. In such case, all
* of the matches must match for the element to take action (so, in the second
* element, both "match-type" and "another-match-type" must be satisfied).
* If there's no match in the element, the action is taken/returned without
* conditions, every time (makes sense as the last entry, as the ACL will
* never get past it).
*
* The second entry shows another thing - if there's a list as the value
* for some match and the match itself is not expecting a list, it is taken
* as an "or" - a match for at last one of the choices in the list must match.
* So, for the second entry, both "match-type" and "another-match-type" must
* be satisfied, but the another one is satisfied by either parameter1 or
* parameter2.
*/
template
<
typename
Context
,
typename
Action
=
BasicAction
>
class
Loader
{
public:
/**
* \brief Constructor.
*
* \param default_action The default action for created ACLs.
* \param actionLoader is the loader which will be used to convert actions
* from their JSON representation. The default value is suitable for
* the BasicAction enum. If you did not specify the second
* template argument, you don't need to specify this loader.
*/
Loader
(
const
Action
&
defaultAction
,
const
boost
::
function1
<
Action
,
data
::
ConstElementPtr
>
&
actionLoader
=
&
defaultActionLoader
)
:
default_action_
(
defaultAction
),
action_loader_
(
actionLoader
)
{}
/**
* \brief Creator of the checks.
*
* This can be registered within the Loader and will be used to create the
* checks. It is expected multiple creators (for multiple types, one can
* handle even multiple names) will be created and registered to support
* range of things we could check. This allows for customizing/extending
* the loader.
*/
class
CheckCreator
{
public:
/**
* \brief List of names supported by this loader.
*
* List of all names for which this loader is able to create the
* checks. There can be multiple names, to support both aliases
* to the same checks and creators capable of creating multiple
* types of checks.
*/
virtual
std
::
vector
<
std
::
string
>
names
()
const
=
0
;
/**
* \brief Creates the check.
*
* This function does the actual creation. It is passed all the
* relevant data and is supposed to return shared pointer to the
* check.
*
* It is expected to throw the LoaderError exception when the
* definition is invalid.
*
* \param name The type name of the check. If the creator creates
* only one type of check, it can safely ignore this parameter.
* \param definition The part of JSON describing the parameters of
* check. As there's no way for the loader to know how the
* parameters might look like, they are not checked in any way.
* Therefore it's up to the creator (or the check being created)
* to validate the data and throw if it is bad.
* \param Current loader calling this creator. This can be used
* to load subexpressions in case of compound check.
*/
virtual
boost
::
shared_ptr
<
Check
<
Context
>
>
create
(
const
std
::
string
&
name
,
data
::
ConstElementPtr
definition
,
const
Loader
<
Context
,
Action
>&
loader
)
=
0
;
/**
* \brief Is list or-abbreviation allowed?
*
* If this returns true and the parameter (eg. the value we check
* against, the one that is passed as the second parameter of create)
* is list, the loader will call the create method with each element of
* the list and aggregate all the results in OR compound check. If it
* is false, the parameter is passed verbatim no matter if it is or
* isn't a list. For example, IP check will have this as true (so
* multiple IP addresses can be passed as options), but AND operator
* will return false and handle the list of subexpressions itself.
*
* The rationale behind this is that it is common to specify list of
* something that matches (eg. list of IP addresses).
*/
virtual
bool
allowListAbbreviation
()
const
{
return
(
true
);
}
};
/**
* \brief Register another check creator.
*
* Adds a creator to the list of known ones. The creator's list of names
* must be disjoint with the names already known to the creator or the
* LoaderError exception is thrown. In such case, the creator is not
* registered under any of the names. In case of other exceptions, like
* bad_alloc, only weak exception safety is guaranteed.
*
* \param creator Shared pointer to the creator.
* \note We don't support deregistration yet, but it is expected it will
* be needed in future, when we have some kind of plugins. These
* plugins might want to unload, in which case they would need to
* deregister their creators. It is expected they would pass the same
* pointer to such method as they pass here.
*/
void
registerCreator
(
boost
::
shared_ptr
<
CheckCreator
>
creator
)
{
// First check we can insert all the names
typedef
std
::
vector
<
std
::
string
>
Strings
;
const
Strings
names
(
creator
->
names
());
for
(
Strings
::
const_iterator
i
(
names
.
begin
());
i
!=
names
.
end
();
++
i
)
{
if
(
creators_
.
find
(
*
i
)
!=
creators_
.
end
())
{
isc_throw
(
LoaderError
,
"The loader already contains creator "
"named "
<<
*
i
);
}
}
// Now insert them
for
(
Strings
::
const_iterator
i
(
names
.
begin
());
i
!=
names
.
end
();
++
i
)
{
creators_
[
*
i
]
=
creator
;
}
}
/**
* \brief Load a check.
*
* This parses a check dict (block, the one element of ACL) and calls a
* creator (or creators, if more than one check is found inside) for it. It
* ignores the "action" key, as it is a reserved keyword used to specify
* actions inside the ACL.
*
* This may throw LoaderError if it is not a dict or if some of the type
* names is not known (there's no creator registered for it). The
* exceptions from creators aren't caught.
*
* \param description The JSON description of the check.
*/
boost
::
shared_ptr
<
Check
<
Context
>
>
loadCheck
(
const
data
::
ConstElementPtr
&
description
)
{
// Get the description as a map
typedef
std
::
map
<
std
::
string
,
data
::
ConstElementPtr
>
Map
;
Map
map
;
try
{
map
=
description
->
mapValue
();
}
catch
(
const
data
::
TypeError
&
)
{
isc_throw_1
(
LoaderError
,
"Check description is not a map"
,
description
);
}
// Call the internal part with extracted map
return
(
loadCheck
(
description
,
map
));
}
/**
* \brief Load an ACL.
*
* This parses an ACL list, creates the checks and actions of each element
* and returns it. It may throw LoaderError if it isn't a list or the
* "action" key is missing in some element. Also, no exceptions from
* loadCheck (therefore from whatever creator is used) and from the
* actionLoader passed to constructor are not caught.
*
* \param description The JSON list of ACL.
*/
boost
::
shared_ptr
<
ACL
<
Context
,
Action
>
>
load
(
const
data
::
ConstElementPtr
&
description
)
{
// We first check it's a list, so we can use the list reference
// (the list may be huge)
if
(
description
->
getType
()
!=
data
::
Element
::
list
)
{
isc_throw_1
(
LoaderError
,
"ACL not a list"
,
description
);
}
// First create an empty ACL
const
List
&
list
(
description
->
listValue
());
boost
::
shared_ptr
<
ACL
<
Context
,
Action
>
>
result
(
new
ACL
<
Context
,
Action
>
(
default_action_
));
// Run trough the list of elements
for
(
List
::
const_iterator
i
(
list
.
begin
());
i
!=
list
.
end
();
++
i
)
{
Map
map
;
try
{
map
=
(
*
i
)
->
mapValue
();
}
catch
(
const
data
::
TypeError
&
)
{
isc_throw_1
(
LoaderError
,
"ACL element not a map"
,
*
i
);
}
// Create an action for the element
const
Map
::
const_iterator
action
(
map
.
find
(
"action"
));
if
(
action
==
map
.
end
())
{
isc_throw_1
(
LoaderError
,
"No action in ACL element"
,
*
i
);
}
const
Action
acValue
(
action_loader_
(
action
->
second
));
// Now create the check if there's one
if
(
map
.
size
()
>=
2
)
{
// One is the action, another one the check
result
->
append
(
loadCheck
(
*
i
,
map
),
acValue
);
}
else
{
// In case there's no check, this matches every time. We
// simulate it by our own private "True" check.
result
->
append
(
boost
::
shared_ptr
<
Check
<
Context
>
>
(
new
True
()),
acValue
);
}
}
return
(
result
);
}
private:
// Some type aliases to save typing
typedef
std
::
map
<
std
::
string
,
boost
::
shared_ptr
<
CheckCreator
>
>
Creators
;
typedef
std
::
map
<
std
::
string
,
data
::
ConstElementPtr
>
Map
;
typedef
std
::
vector
<
data
::
ConstElementPtr
>
List
;
// Private members
Creators
creators_
;
const
Action
default_action_
;
const
boost
::
function1
<
Action
,
data
::
ConstElementPtr
>
action_loader_
;
/**
* \brief Internal version of loadCheck.
*
* This is the internal part, shared between load and loadCheck.
* \param description The bit of JSON (used in exceptions).
* \param map The extracted map describing the check. It does change
* the map.
*/
boost
::
shared_ptr
<
Check
<
Context
>
>
loadCheck
(
const
data
::
ConstElementPtr
&
description
,
Map
&
map
)
{
// Remove the action keyword
map
.
erase
(
"action"
);
// Now, do we have any definition? Or is it and abbreviation?
switch
(
map
.
size
())
{
case
0
:
isc_throw_1
(
LoaderError
,
"Check description is empty"
,
description
);
case
1
:
{
// Get the first and only item
const
Map
::
const_iterator
checkDesc
(
map
.
begin
());
const
std
::
string
&
name
(
checkDesc
->
first
);
const
typename
Creators
::
const_iterator
creatorIt
(
creators_
.
find
(
name
));
if
(
creatorIt
==
creators_
.
end
())
{
isc_throw_1
(
LoaderError
,
"No creator for ACL check "
<<
name
,
description
);
}
if
(
creatorIt
->
second
->
allowListAbbreviation
()
&&
checkDesc
->
second
->
getType
()
==
data
::
Element
::
list
)
{
isc_throw_1
(
LoaderError
,
"Not implemented (OR-abbreviated form)"
,
checkDesc
->
second
);
}
// Create the check and return it
return
(
creatorIt
->
second
->
create
(
name
,
checkDesc
->
second
,
*
this
));
}
default:
isc_throw_1
(
LoaderError
,
"Not implemented (AND-abbreviated form)"
,
description
);
}
}
/**
* \brief Check that always matches.
*
* This one is used internally for ACL elements without condition. We may
* want to make this publicly accesible sometime maybe, but for now,
* there's no need.
*/
class
True
:
public
Check
<
Context
>
{
public:
virtual
bool
matches
(
const
Context
&
)
const
{
return
(
true
);
};
virtual
unsigned
cost
()
const
{
return
(
1
);
}
// We don't write "true" here, as this one was created using empty
// input
virtual
std
::
string
toText
()
const
{
return
""
;
}
};
};
}
}
#endif
src/lib/acl/tests/Makefile.am
View file @
926a65fa
...
...
@@ -5,12 +5,16 @@ TESTS =
if
HAVE_GTEST
TESTS
+=
run_unittests
run_unittests_SOURCES
=
run_unittests.cc
run_unittests_SOURCES
+=
check_test.cc acl_test.cc
run_unittests_SOURCES
+=
check_test.cc acl_test.cc loader_test.cc
run_unittests_SOURCES
+=
logcheck.h
run_unittests_CPPFLAGS
=
$(AM_CPPFLAGS)
$(GTEST_INCLUDES)
run_unittests_LDFLAGS
=
$(AM_LDFLAGS)
$(GTEST_LDFLAGS)
run_unittests_LDADD
=
$(GTEST_LDADD)
run_unittests_LDADD
+=
$(top_builddir)
/src/lib/util/unittests/libutil_unittests.la
run_unittests_LDADD
+=
$(top_builddir)
/src/lib/acl/libacl.la
run_unittests_LDADD
+=
$(top_builddir)
/src/lib/cc/libcc.la
run_unittests_LDADD
+=
$(top_builddir)
/src/lib/exceptions/libexceptions.la
endif
noinst_PROGRAMS
=
$(TESTS)
src/lib/acl/tests/acl_test.cc
View file @
926a65fa
...
...
@@ -12,75 +12,11 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include
<gtest/gtest.h>
#include
<acl/acl.h>
#include
<cassert>
using
namespace
isc
::
acl
;
using
boost
::
shared_ptr
;
#include
"logcheck.h"
namespace
{
// This is arbitrary guess of size for the log. If it's too small for your
// test, just make it bigger.
const
size_t
LOG_SIZE
=
10
;
// This will remember which checks did run already.
struct
Log
{
// The actual log cells, if i-th check did run
mutable
bool
run
[
LOG_SIZE
];
Log
()
{
// Nothing run yet
for
(
size_t
i
(
0
);
i
<
LOG_SIZE
;
++
i
)
{
run
[
i
]
=
false
;
}
}
// Checks that the first amount of checks did run and the rest didn't.
void
checkFirst
(
size_t
amount
)
const
{
ASSERT_LE
(
amount
,
LOG_SIZE
)
<<
"Wrong test: amount bigger than size "
"of log"
;
{
SCOPED_TRACE
(
"Checking that the first amount of checks did run"
);
for
(
size_t
i
(
0
);
i
<
amount
;
++
i
)
{
EXPECT_TRUE
(
run
[
i
])
<<
"Check #"
<<
i
<<
" did not run."
;
}
}
{
SCOPED_TRACE
(
"Checking that the rest did not run"
);
for
(
size_t
i
(
amount
);
i
<
LOG_SIZE
;
++
i
)
{
EXPECT_FALSE
(
run
[
i
])
<<
"Check #"
<<
i
<<
"did run."
;
}
}
}
};
// This returns true or false every time, no matter what is passed to it.
// But it logs that it did run.
class
ConstCheck
:
public
Check
<
Log
>
{
public:
ConstCheck
(
bool
accepts
,
size_t
log_num
)
:
log_num_
(
log_num
),
accepts_
(
accepts
)
{
assert
(
log_num
<
LOG_SIZE
);
// If this fails, the LOG_SIZE is too small
}
/*
* This use of mutable log context is abuse for testing purposes.
* It is expected that the context will not be modified in the real
* applications of ACLs, but we want to know which checks were called
* and this is an easy way.
*/
virtual
bool
matches
(
const
Log
&
log
)
const
{
log
.
run
[
log_num_
]
=
true
;
return
(
accepts_
);
}
private:
size_t
log_num_
;
bool
accepts_
;
};
// Test version of the ACL class. It adds few methods to examine the protected
// Test version of the Acl class. It adds few methods to examine the protected
// data, but does not change the implementation.
class
TestACL
:
public
ACL
<
Log
>
{
public:
...
...
src/lib/acl/tests/loader_test.cc
0 → 100644
View file @
926a65fa
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include
"logcheck.h"
#include
<acl/loader.h>
#include
<string>
#include
<gtest/gtest.h>
using
namespace
std
;
using
namespace
boost
;
using
isc
::
data
::
ConstElementPtr
;
namespace
{
// Just for convenience, create JSON objects from JSON string
ConstElementPtr
el
(
const
string
&
JSON
)
{
return
(
isc
::
data
::
Element
::
fromJSON
(
JSON
));
}
// We don't use the EXPECT_THROW macro, as it doesn't allow us
// to examine the exception. We want to check the element is stored
// there as well.
void
testActionLoaderException
(
const
string
&
JSON
)
{
SCOPED_TRACE
(
"Should throw with input: "
+
JSON
);
ConstElementPtr
elem
(
el
(
JSON
));
try
{
defaultActionLoader
(
elem
);
FAIL
()
<<
"It did not throw"
;
}
catch
(
const
LoaderError
&
error
)
{
// Yes, comparing for pointer equality, that is enough, it
// should return the exact instance of the JSON object
EXPECT_EQ
(
elem
,
error
.
element
());
}