Skip to content
GitLab
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
d10df14d
Commit
d10df14d
authored
May 22, 2012
by
JINMEI Tatuya
Browse files
[master] Merge branch 'trac1539-2' with fixing minor conflicts.
parents
18faaf14
fd12fc92
Changes
20
Hide whitespace changes
Inline
Side-by-side
src/bin/auth/auth_messages.mes
View file @
d10df14d
...
...
@@ -255,6 +255,20 @@ processed by the authoritative server has been found to contain an
unsupported opcode. (The opcode is included in the message.) The server
will return an error code of NOTIMPL to the sender.
% AUTH_MESSAGE_FORWARD_ERROR failed to forward %1 request from %2: %3
The authoritative server tried to forward some type DNS request
message to a separate process (e.g., forwarding dynamic update
requests to b10-ddns) to handle it, but it failed. The authoritative
server returns SERVFAIL to the client on behalf of the separate
process. The error could be configuration mismatch between b10-auth
and the recipient component, or it may be because the requests are
coming too fast and the receipient process cannot keep up with the
rate, or some system level failure. In either case this means the
BIND 10 system is not working as expected, so the administrator should
look into the cause and address the issue. The log message includes
the client's address (and port), and the error message sent from the
lower layer that detects the failure.
% AUTH_XFRIN_CHANNEL_CREATED XFRIN session channel created
This is a debug message indicating that the authoritative server has
created a channel to the XFRIN (Transfer-in) process. It is issued
...
...
src/bin/auth/auth_srv.cc
View file @
d10df14d
...
...
@@ -14,18 +14,10 @@
#include
<config.h>
#include
<sys/types.h>
#include
<netinet/in.h>
#include
<algorithm>
#include
<cassert>
#include
<iostream>
#include
<vector>
#include
<memory>
#include
<boost/bind.hpp>
#include
<util/io/socketsession.h>
#include
<asiolink/asiolink.h>
#include
<asiolink/io_endpoint.h>
#include
<config/ccsession.h>
...
...
@@ -64,6 +56,18 @@
#include
<auth/statistics.h>
#include
<auth/auth_log.h>
#include
<boost/bind.hpp>
#include
<boost/lexical_cast.hpp>
#include
<algorithm>
#include
<cassert>
#include
<iostream>
#include
<vector>
#include
<memory>
#include
<sys/types.h>
#include
<netinet/in.h>
using
namespace
std
;
using
namespace
isc
;
...
...
@@ -71,6 +75,7 @@ using namespace isc::cc;
using
namespace
isc
::
datasrc
;
using
namespace
isc
::
dns
;
using
namespace
isc
::
util
;
using
namespace
isc
::
util
::
io
;
using
namespace
isc
::
auth
;
using
namespace
isc
::
dns
::
rdata
;
using
namespace
isc
::
data
;
...
...
@@ -107,6 +112,107 @@ public:
private:
MessageRenderer
&
renderer_
;
};
// A helper container of socket session forwarder.
//
// This class provides a simple wrapper interface to SocketSessionForwarder
// so that the caller doesn't have to worry about connection management,
// exception handling or parameter building.
//
// It internally maintains whether the underlying forwarder establishes a
// connection to the receiver. On a forwarding request, if the connection
// hasn't been established yet, it automatically opens a new one, then
// pushes the session over it. It also closes the connection on destruction,
// or a non-recoverable error happens, automatically. So the only thing
// the application has to do is to create this object and push any session
// to be forwarded.
class
SocketSessionForwarderHolder
{
public:
/// \brief The constructor.
///
/// \param message_name Any string that can identify the type of messages
/// to be forwarded via this session. It will be only used as part of
/// log message, so it can be anything, but in practice something like
/// "update" or "xfr" is expected.
/// \param forwarder The underlying socket session forwarder.
SocketSessionForwarderHolder
(
const
string
&
message_name
,
BaseSocketSessionForwarder
&
forwarder
)
:
message_name_
(
message_name
),
forwarder_
(
forwarder
),
connected_
(
false
)
{}
~
SocketSessionForwarderHolder
()
{
if
(
connected_
)
{
forwarder_
.
close
();
}
}
/// \brief Push a socket session corresponding to given IOMessage.
///
/// If the connection with the receiver process hasn't been established,
/// it automatically establishes one, then push the session over it.
///
/// If either connect or push fails, the underlying forwarder object should
/// throw an exception. This method logs the event, and propagates the
/// exception to the caller, which will eventually result in SERVFAIL.
/// The connection, if established, is automatically closed, so the next
/// forward request will trigger reopening a new connection.
///
/// \note: Right now, there's no API to retrieve the local address from
/// the IOMessage. Until it's added, we pass the remote address as
/// local.
///
/// \param io_message The request message to be forwarded as a socket
/// session. It will be converted to the parameters that the underlying
/// SocketSessionForwarder expects.
void
push
(
const
IOMessage
&
io_message
)
{
const
IOEndpoint
&
remote_ep
=
io_message
.
getRemoteEndpoint
();
const
int
protocol
=
remote_ep
.
getProtocol
();
const
int
sock_type
=
getSocketType
(
protocol
);
try
{
connect
();
forwarder_
.
push
(
io_message
.
getSocket
().
getNative
(),
remote_ep
.
getFamily
(),
sock_type
,
protocol
,
remote_ep
.
getSockAddr
(),
remote_ep
.
getSockAddr
(),
io_message
.
getData
(),
io_message
.
getDataSize
());
}
catch
(
const
SocketSessionError
&
ex
)
{
LOG_ERROR
(
auth_logger
,
AUTH_MESSAGE_FORWARD_ERROR
).
arg
(
message_name_
).
arg
(
remote_ep
).
arg
(
ex
.
what
());
close
();
throw
;
}
}
private:
const
string
message_name_
;
BaseSocketSessionForwarder
&
forwarder_
;
bool
connected_
;
void
connect
()
{
if
(
!
connected_
)
{
forwarder_
.
connectToReceiver
();
connected_
=
true
;
}
}
void
close
()
{
if
(
connected_
)
{
forwarder_
.
close
();
connected_
=
false
;
}
}
static
int
getSocketType
(
int
protocol
)
{
switch
(
protocol
)
{
case
IPPROTO_UDP
:
return
(
SOCK_DGRAM
);
case
IPPROTO_TCP
:
return
(
SOCK_STREAM
);
default:
isc_throw
(
isc
::
InvalidParameter
,
"Unexpected socket address family: "
<<
protocol
);
}
}
};
}
class
AuthSrvImpl
{
...
...
@@ -115,7 +221,8 @@ private:
AuthSrvImpl
(
const
AuthSrvImpl
&
source
);
AuthSrvImpl
&
operator
=
(
const
AuthSrvImpl
&
source
);
public:
AuthSrvImpl
(
const
bool
use_cache
,
AbstractXfroutClient
&
xfrout_client
);
AuthSrvImpl
(
const
bool
use_cache
,
AbstractXfroutClient
&
xfrout_client
,
BaseSocketSessionForwarder
&
ddns_forwarder
);
~
AuthSrvImpl
();
isc
::
data
::
ConstElementPtr
setDbFile
(
isc
::
data
::
ConstElementPtr
config
);
...
...
@@ -128,6 +235,7 @@ public:
bool
processNotify
(
const
IOMessage
&
io_message
,
Message
&
message
,
OutputBuffer
&
buffer
,
auto_ptr
<
TSIGContext
>
tsig_context
);
bool
processUpdate
(
const
IOMessage
&
io_message
);
IOService
io_service_
;
...
...
@@ -189,6 +297,9 @@ private:
bool
xfrout_connected_
;
AbstractXfroutClient
&
xfrout_client_
;
// Socket session forwarder for dynamic update requests
SocketSessionForwarderHolder
ddns_forwarder_
;
/// Increment query counter
void
incCounter
(
const
int
protocol
);
...
...
@@ -199,7 +310,8 @@ private:
};
AuthSrvImpl
::
AuthSrvImpl
(
const
bool
use_cache
,
AbstractXfroutClient
&
xfrout_client
)
:
AbstractXfroutClient
&
xfrout_client
,
BaseSocketSessionForwarder
&
ddns_forwarder
)
:
config_session_
(
NULL
),
xfrin_session_
(
NULL
),
memory_client_class_
(
RRClass
::
IN
()),
...
...
@@ -207,7 +319,8 @@ AuthSrvImpl::AuthSrvImpl(const bool use_cache,
counters_
(),
keyring_
(
NULL
),
xfrout_connected_
(
false
),
xfrout_client_
(
xfrout_client
)
xfrout_client_
(
xfrout_client
),
ddns_forwarder_
(
"update"
,
ddns_forwarder
)
{
// cur_datasrc_ is automatically initialized by the default constructor,
// effectively being an empty (sqlite) data source. once ccsession is up
...
...
@@ -277,9 +390,10 @@ private:
AuthSrv
*
server_
;
};
AuthSrv
::
AuthSrv
(
const
bool
use_cache
,
AbstractXfroutClient
&
xfrout_client
)
AuthSrv
::
AuthSrv
(
const
bool
use_cache
,
AbstractXfroutClient
&
xfrout_client
,
BaseSocketSessionForwarder
&
ddns_forwarder
)
{
impl_
=
new
AuthSrvImpl
(
use_cache
,
xfrout_client
);
impl_
=
new
AuthSrvImpl
(
use_cache
,
xfrout_client
,
ddns_forwarder
);
checkin_
=
new
ConfigChecker
(
this
);
dns_lookup_
=
new
MessageLookup
(
this
);
dns_answer_
=
new
MessageAnswer
(
this
);
...
...
@@ -527,16 +641,19 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
return
;
}
const
Opcode
opcode
=
message
.
getOpcode
();
bool
send_answer
=
true
;
try
{
// update per opcode statistics counter. This can only be reliable
// after TSIG check succeeds.
impl_
->
counters_
.
inc
(
message
.
getOpcode
());
if
(
message
.
getO
pcode
()
==
Opcode
::
NOTIFY
())
{
if
(
o
pcode
==
Opcode
::
NOTIFY
())
{
send_answer
=
impl_
->
processNotify
(
io_message
,
message
,
buffer
,
tsig_context
);
}
else
if
(
message
.
getOpcode
()
!=
Opcode
::
QUERY
())
{
}
else
if
(
opcode
==
Opcode
::
UPDATE
())
{
send_answer
=
impl_
->
processUpdate
(
io_message
);
}
else
if
(
opcode
!=
Opcode
::
QUERY
())
{
LOG_DEBUG
(
auth_logger
,
DBG_AUTH_DETAIL
,
AUTH_UNSUPPORTED_OPCODE
)
.
arg
(
message
.
getOpcode
().
toText
());
makeErrorMessage
(
impl_
->
renderer_
,
message
,
buffer
,
...
...
@@ -546,7 +663,7 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
Rcode
::
FORMERR
(),
tsig_context
);
}
else
{
ConstQuestionPtr
question
=
*
message
.
beginQuestion
();
const
RRType
&
qtype
=
question
->
getType
();
const
RRType
&
qtype
=
question
->
getType
();
if
(
qtype
==
RRType
::
AXFR
())
{
send_answer
=
impl_
->
processXfrQuery
(
io_message
,
message
,
buffer
,
tsig_context
);
...
...
@@ -754,6 +871,15 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
return
(
true
);
}
bool
AuthSrvImpl
::
processUpdate
(
const
IOMessage
&
io_message
)
{
// Push the update request to a separate process via the forwarder.
// On successful push, the request shouldn't be responded from b10-auth,
// so we return false.
ddns_forwarder_
.
push
(
io_message
);
return
(
false
);
}
void
AuthSrvImpl
::
incCounter
(
const
int
protocol
)
{
// Increment query counter.
...
...
src/bin/auth/auth_srv.h
View file @
d10df14d
...
...
@@ -37,6 +37,14 @@
#include
<auth/statistics.h>
namespace
isc
{
namespace
util
{
namespace
io
{
class
BaseSocketSessionForwarder
;
}
}
namespace
datasrc
{
class
InMemoryClient
;
}
namespace
xfr
{
class
AbstractXfroutClient
;
}
...
...
@@ -90,7 +98,8 @@ public:
/// but can refer to a local mock object for testing (or other
/// experimental) purposes.
AuthSrv
(
const
bool
use_cache
,
isc
::
xfr
::
AbstractXfroutClient
&
xfrout_client
);
isc
::
xfr
::
AbstractXfroutClient
&
xfrout_client
,
isc
::
util
::
io
::
BaseSocketSessionForwarder
&
ddns_forwarder
);
~
AuthSrv
();
//@}
...
...
src/bin/auth/benchmarks/query_bench.cc
View file @
d10df14d
...
...
@@ -31,9 +31,10 @@
#include
<dns/rrclass.h>
#include
<log/logger_support.h>
#include
<xfr/xfrout_client.h>
#include
<util/unittests/mock_socketsession.h>
#include
<auth/auth_srv.h>
#include
<auth/auth_config.h>
#include
<auth/query.h>
...
...
@@ -48,6 +49,7 @@ using namespace isc::auth;
using
namespace
isc
::
dns
;
using
namespace
isc
::
log
;
using
namespace
isc
::
util
;
using
namespace
isc
::
util
::
unittests
;
using
namespace
isc
::
xfr
;
using
namespace
isc
::
bench
;
using
namespace
isc
::
asiodns
;
...
...
@@ -78,7 +80,7 @@ protected:
QueryBenchMark
(
const
bool
enable_cache
,
const
BenchQueries
&
queries
,
Message
&
query_message
,
OutputBuffer
&
buffer
)
:
server_
(
new
AuthSrv
(
enable_cache
,
xfrout_client
)),
server_
(
new
AuthSrv
(
enable_cache
,
xfrout_client
,
ddns_forwarder
)),
queries_
(
queries
),
query_message_
(
query_message
),
buffer_
(
buffer
),
...
...
@@ -103,6 +105,8 @@ public:
return
(
queries_
.
size
());
}
private:
MockSocketSessionForwarder
ddns_forwarder
;
protected:
AuthSrvPtr
server_
;
private:
...
...
src/bin/auth/common.cc
View file @
d10df14d
...
...
@@ -33,7 +33,25 @@ getXfroutSocketPath() {
if
(
getenv
(
"BIND10_XFROUT_SOCKET_FILE"
)
!=
NULL
)
{
return
(
getenv
(
"BIND10_XFROUT_SOCKET_FILE"
));
}
else
{
return
(
UNIX_SOCKET_FILE
);
return
(
UNIX_XFROUT_SOCKET_FILE
);
}
}
}
string
getDDNSSocketPath
()
{
if
(
getenv
(
"B10_FROM_BUILD"
)
!=
NULL
)
{
if
(
getenv
(
"B10_FROM_SOURCE_LOCALSTATEDIR"
)
!=
NULL
)
{
return
(
string
(
getenv
(
"B10_FROM_SOURCE_LOCALSTATEDIR"
))
+
"/ddns_socket"
);
}
else
{
return
(
string
(
getenv
(
"B10_FROM_BUILD"
))
+
"/ddns_socket"
);
}
}
else
{
if
(
getenv
(
"BIND10_DDNS_SOCKET_FILE"
)
!=
NULL
)
{
return
(
getenv
(
"BIND10_DDNS_SOCKET_FILE"
));
}
else
{
return
(
UNIX_DDNS_SOCKET_FILE
);
}
}
}
...
...
src/bin/auth/common.h
View file @
d10df14d
...
...
@@ -38,6 +38,20 @@ public:
/// The logic should be the same as in b10-xfrout, so they find each other.
std
::
string
getXfroutSocketPath
();
/// \brief Get the path of socket to talk to ddns
///
/// It takes some environment variables into account (B10_FROM_BUILD,
/// B10_FROM_SOURCE_LOCALSTATEDIR and BIND10_DDNS_SOCKET_FILE). It
/// also considers the installation prefix.
///
/// The logic should be the same as in b10-ddns, so they find each other.
///
/// Note: eventually we should find a better way so that we don't have to
/// repeat the same magic value (and how to tweak it with some magic
/// environment variable) twice, at which point this function may be able
/// to be deprecated.
std
::
string
getDDNSSocketPath
();
/// \brief The name used when identifieng the process
///
/// This is currently b10-auth, but it can be changed easily in one place.
...
...
src/bin/auth/main.cc
View file @
d10df14d
...
...
@@ -28,6 +28,7 @@
#include
<exceptions/exceptions.h>
#include
<util/buffer.h>
#include
<util/io/socketsession.h>
#include
<dns/message.h>
#include
<dns/messagerenderer.h>
...
...
@@ -60,6 +61,7 @@ using namespace isc::data;
using
namespace
isc
::
dns
;
using
namespace
isc
::
log
;
using
namespace
isc
::
util
;
using
namespace
isc
::
util
::
io
;
using
namespace
isc
::
xfr
;
namespace
{
...
...
@@ -130,6 +132,7 @@ main(int argc, char* argv[]) {
bool
statistics_session_established
=
false
;
// XXX (see Trac #287)
ModuleCCSession
*
config_session
=
NULL
;
XfroutClient
xfrout_client
(
getXfroutSocketPath
());
SocketSessionForwarder
ddns_forwarder
(
getDDNSSocketPath
());
try
{
string
specfile
;
if
(
getenv
(
"B10_FROM_BUILD"
))
{
...
...
@@ -139,7 +142,7 @@ main(int argc, char* argv[]) {
specfile
=
string
(
AUTH_SPECFILE_LOCATION
);
}
auth_server
=
new
AuthSrv
(
cache
,
xfrout_client
);
auth_server
=
new
AuthSrv
(
cache
,
xfrout_client
,
ddns_forwarder
);
LOG_INFO
(
auth_logger
,
AUTH_SERVER_CREATED
);
SimpleCallback
*
checkin
=
auth_server
->
getCheckinProvider
();
...
...
src/bin/auth/spec_config.h.pre.in
View file @
d10df14d
...
...
@@ -13,4 +13,5 @@
// PERFORMANCE OF THIS SOFTWARE.
#define AUTH_SPECFILE_LOCATION "@prefix@/share/@PACKAGE@/auth.spec"
#define UNIX_SOCKET_FILE "@@LOCALSTATEDIR@@/@PACKAGE@/auth_xfrout_conn"
#define UNIX_XFROUT_SOCKET_FILE "@@LOCALSTATEDIR@@/@PACKAGE@/auth_xfrout_conn"
#define UNIX_DDNS_SOCKET_FILE "@@LOCALSTATEDIR@@/@PACKAGE@/ddns_socket"
src/bin/auth/tests/auth_srv_unittest.cc
View file @
d10df14d
...
...
@@ -14,12 +14,7 @@
#include
<config.h>
#include
<vector>
#include
<boost/shared_ptr.hpp>
#include
<boost/scoped_ptr.hpp>
#include
<gtest/gtest.h>
#include
<util/io/sockaddr_util.h>
#include
<dns/message.h>
#include
<dns/messagerenderer.h>
...
...
@@ -39,6 +34,7 @@
#include
<auth/common.h>
#include
<auth/statistics.h>
#include
<util/unittests/mock_socketsession.h>
#include
<dns/tests/unittest_util.h>
#include
<testutils/dnsmessage_test.h>
#include
<testutils/srv_test.h>
...
...
@@ -46,10 +42,24 @@
#include
<testutils/portconfig.h>
#include
<testutils/socket_request.h>
#include
<gtest/gtest.h>
#include
<boost/lexical_cast.hpp>
#include
<boost/shared_ptr.hpp>
#include
<boost/scoped_ptr.hpp>
#include
<vector>
#include
<sys/types.h>
#include
<sys/socket.h>
#include
<netdb.h>
using
namespace
std
;
using
namespace
isc
::
cc
;
using
namespace
isc
::
dns
;
using
namespace
isc
::
util
;
using
namespace
isc
::
util
::
io
::
internal
;
using
namespace
isc
::
util
::
unittests
;
using
namespace
isc
::
dns
::
rdata
;
using
namespace
isc
::
data
;
using
namespace
isc
::
xfr
;
...
...
@@ -58,6 +68,7 @@ using namespace isc::asiolink;
using
namespace
isc
::
testutils
;
using
namespace
isc
::
server_common
::
portconfig
;
using
isc
::
UnitTestUtil
;
using
boost
::
scoped_ptr
;
namespace
{
const
char
*
const
CONFIG_TESTDB
=
...
...
@@ -78,7 +89,7 @@ class AuthSrvTest : public SrvTestBase {
protected:
AuthSrvTest
()
:
dnss_
(),
server
(
true
,
xfrout
),
server
(
true
,
xfrout
,
ddns_forwarder
),
rrclass
(
RRClass
::
IN
()),
// The empty string is expected value of the parameter of
// requestSocket, not the app_name (there's no fallback, it checks
...
...
@@ -144,9 +155,30 @@ protected:
opcode
.
getCode
(),
QR_FLAG
,
1
,
0
,
0
,
0
);
}
// Convenient shortcut of creating a simple request and having the
// server process it.
void
createAndSendRequest
(
RRType
req_type
,
Opcode
opcode
=
Opcode
::
QUERY
(),
const
Name
&
req_name
=
Name
(
"example.com"
),
RRClass
req_class
=
RRClass
::
IN
(),
int
protocol
=
IPPROTO_UDP
,
const
char
*
const
remote_address
=
DEFAULT_REMOTE_ADDRESS
,
uint16_t
remote_port
=
DEFAULT_REMOTE_PORT
)
{
UnitTestUtil
::
createRequestMessage
(
request_message
,
opcode
,
default_qid
,
req_name
,
req_class
,
req_type
);
createRequestPacket
(
request_message
,
protocol
,
NULL
,
remote_address
,
remote_port
);
parse_message
->
clear
(
Message
::
PARSE
);
server
.
processMessage
(
*
io_message
,
*
parse_message
,
*
response_obuffer
,
&
dnsserv
);
}
MockDNSService
dnss_
;
MockSession
statistics_session
;
MockXfroutClient
xfrout
;
MockSocketSessionForwarder
ddns_forwarder
;
AuthSrv
server
;
const
RRClass
rrclass
;
vector
<
uint8_t
>
response_data
;
...
...
@@ -254,8 +286,8 @@ TEST_F(AuthSrvTest, iqueryViaDNSServer) {
// Unsupported requests. Should result in NOTIMP.
TEST_F
(
AuthSrvTest
,
unsupportedRequest
)
{
unsupportedRequest
();
// unsupportedRequest tries 1
4
different opcodes
checkAllRcodeCountersZeroExcept
(
Rcode
::
NOTIMP
(),
1
4
);
// unsupportedRequest tries 1
3
different opcodes
checkAllRcodeCountersZeroExcept
(
Rcode
::
NOTIMP
(),
1
3
);
}
// Multiple questions. Should result in FORMERR.
...
...
@@ -1488,4 +1520,128 @@ TEST_F(AuthSrvTest,
opcode
.
getCode
(),
QR_FLAG
,
1
,
0
,
0
,
0
);
}
//
// DDNS related tests
//
// Helper subroutine to check if the given socket address has the expected
// address and port. It depends on specific output of getnameinfo() (while
// there can be multiple textual representation of the same address) but
// in practice it should be reliable.
void
checkAddrPort
(
const
struct
sockaddr
&
actual_sa
,
const
string
&
expected_addr
,
uint16_t
expected_port
)
{
char
hbuf
[
NI_MAXHOST
],
sbuf
[
NI_MAXSERV
];
const
int
error
=
getnameinfo
(
&
actual_sa
,
getSALength
(
actual_sa
),
hbuf
,
sizeof
(
hbuf
),
sbuf
,
sizeof
(
sbuf
),
NI_NUMERICHOST
|
NI_NUMERICSERV
);
if
(
error
!=
0
)
{
isc_throw
(
isc
::
Unexpected
,
"getnameinfo failed: "
<<
gai_strerror
(
error
));
}
EXPECT_EQ
(
expected_addr
,
hbuf
);
EXPECT_EQ
(
boost
::
lexical_cast
<
string
>
(
expected_port
),
sbuf
);
}
TEST_F
(
AuthSrvTest
,
DDNSForward
)
{
EXPECT_FALSE
(
ddns_forwarder
.
isConnected
());
// Repeat sending an update request 4 times, differing some network
// parameters: UDP/IPv4, TCP/IPv4, UDP/IPv6, TCP/IPv6, in this order.
// By doing that we can also confirm the forwarder connection will be
// established exactly once, and kept established.
for
(
size_t
i
=
0
;
i
<
4
;
++
i
)
{
// Use different names for some different cases
const
Name
zone_name
=
Name
(
i
<
2
?
"example.com"
:
"example.org"
);
const
socklen_t
family
=
(
i
<
2
)
?
AF_INET
:
AF_INET6
;
const
char
*
const
remote_addr
=
(
family
==
AF_INET
)
?
"192.0.2.1"
:
"2001:db8::1"
;
const
uint16_t
remote_port
=
(
family
==
AF_INET
)
?
53214
:
53216
;
const
int
protocol
=
((
i
%
2
)
==
0
)
?
IPPROTO_UDP
:
IPPROTO_TCP
;
createAndSendRequest
(
RRType
::
SOA
(),
Opcode
::
UPDATE
(),
zone_name
,
RRClass
::
IN
(),
protocol
,
remote_addr
,
remote_port
);
EXPECT_FALSE
(
dnsserv
.
hasAnswer
());
EXPECT_TRUE
(
ddns_forwarder
.
isConnected
());
// Examine the pushed data (note: currently "local end" has a dummy
// value equal to remote)
EXPECT_EQ
(
family
,
ddns_forwarder
.
getPushedFamily
());
const
int
expected_type
=
(
protocol
==
IPPROTO_UDP
)
?
SOCK_DGRAM
:
SOCK_STREAM
;
EXPECT_EQ
(
expected_type
,
ddns_forwarder
.
getPushedType
());
EXPECT_EQ
(
protocol
,
ddns_forwarder
.
getPushedProtocol
());
checkAddrPort
(
ddns_forwarder
.
getPushedRemoteend
(),
remote_addr
,
remote_port
);
checkAddrPort
(
ddns_forwarder
.
getPushedLocalend
(),
remote_addr
,
remote_port
);
EXPECT_EQ
(
io_message
->
getDataSize
(),
ddns_forwarder
.
getPushedData
().
size
());
EXPECT_EQ
(
0
,
memcmp
(
io_message
->
getData
(),
&
ddns_forwarder
.
getPushedData
()[
0
],
ddns_forwarder
.
getPushedData
().
size
()));
}
}
TEST_F
(
AuthSrvTest
,
DDNSForwardConnectFail
)
{
// make connect attempt fail. It should result in SERVFAIL. Note that
// the question (zone) section should be cleared for opcode of update.
ddns_forwarder
.
disableConnect
();
createAndSendRequest
(
RRType
::
SOA
(),
Opcode
::
UPDATE
());
EXPECT_TRUE
(
dnsserv
.
hasAnswer
());
headerCheck
(
*
parse_message
,
default_qid
,
Rcode
::
SERVFAIL
(),
Opcode
::
UPDATE
().
getCode
(),
QR_FLAG
,
0
,
0
,
0
,
0
);
EXPECT_FALSE
(
ddns_forwarder
.
isConnected
());
// Now make connect okay again. Despite the previous failure the new
// connection should now be established.
ddns_forwarder
.
enableConnect
();
createAndSendRequest
(
RRType
::
SOA
(),
Opcode
::
UPDATE
());
EXPECT_FALSE
(
dnsserv
.
hasAnswer
());
EXPECT_TRUE
(
ddns_forwarder
.
isConnected
());