BIND 10 #2765: b10-dhcp4 silently fails if bootp/dhcp4 port is already used on one interface
BIND 10 Development
do-not-reply at isc.org
Tue Dec 3 15:24:28 UTC 2013
#2765: b10-dhcp4 silently fails if bootp/dhcp4 port is already used on one
interface
-------------------------------------+-------------------------------------
Reporter: cas | Owner:
Type: defect | marcin
Priority: medium | Status:
Component: dhcp4 | reviewing
Keywords: | Milestone:
Sensitive: 0 | Sprint-DHCP-20131204
Sub-Project: DHCP | Resolution:
Estimated Difficulty: 0 | CVSS Scoring:
Total Hours: 0 | Defect Severity: N/A
| Feature Depending on Ticket:
| Add Hours to Ticket: 0
| Internal?: 0
-------------------------------------+-------------------------------------
Changes (by tmark):
* owner: tmark => marcin
Comment:
Replying to [comment:12 marcin]:
> Replying to [comment:11 tmark]:
> > This was tricky bit of work. The use of the error handler is a good
approach.
>
> Thanks.
>
> I apologize but I had one outstanding commit which adds a new paragraph
to the developer's guide. I forgot to push this commit prior to the review
that you have done. I pushed it now.
>
> >
> >
-------------------------------------------------------------------------
> > pkt_filter.h and pkt_filter.cc
> >
> > Please check your line width. Quite a few comment lines that spill
over 80.
>
> Fixed.
>
> >
> >
-------------------------------------------------------------------------
> > pkt_filter.h
> >
> > openFallbackSocket() has no @throw.
>
> Added
>
> >
> >
-------------------------------------------------------------------------
> > pkt_filter_inet.h -
> >
> > Commentary for openSocket() has no @throw. Neither does receive(),
nor send().
>
> Added.
> One comment: in some cases it is a rat hole to add throw tags for all
types of exceptions being thrown because they very much depend on the
exceptions thrown by functions they call. Even worse, exceptions thrown by
functions being called from the particular function may change and all
dependent throw tags would have to be updated accordingly.
Agreed, there is a practical limit, however I think it is important to
state
that a method may result in a throw, even indirectly. I believe I have
used commentary to the effect "@throw Does not throw directly, but
underlying functions may.".
>
> >
> >
-------------------------------------------------------------------------
> > pkt_filter.cc
> >
> > openFallbackSocket()
> >
> > You may wish to consider adding use of strerror(errno) as was done
recently in
> > iface_mgr.cc. As it stands, if there are errors there is no OS level
reason
> > for the failure.
>
> I consider it a good idea. So, I added it.
>
Marcin, this is one potential issue in the manner you're accessing errno.
When you call close() on the socket, this may set errno to reflect the
outcome
of the close. If that doesn't, the code produced by the logger macro
might.
The most reliably thing to do is to grab the error message immediately
following the failed function:
{{{
if (bind(sock, reinterpret_cast<struct sockaddr*>(&addr4),
sizeof(addr4)) < 0) {
// Remember to close the socket if we failed to bind it.
const char* errstr = strerror(errno);
close(sock);
isc_throw(SocketConfigError, "failed to bind fallback socket to"
" address " << addr.toText() << ", port " << port
<< ", reason: " << errstr
<< " - is another DHCP server running?");
}
}}}
> >
> >
-------------------------------------------------------------------------
> > pkt_filter_lpf.cc
> >
> > In openSocket(), Why do this?
> >
> > {{{
> > SocketInfo sock_desc(addr, port, sock, fallback);
> > return (sock_desc);
> > }}}
> >
> > instead of:
> >
> > {{{
> > return (SocketInfo sock_desc(addr, port, sock, fallback));
> > }}}
> >
> > Doing it your way, creates a copy locally only to then copies it onto
the stack
> > to return it; instead of making it directly on the stack? It is also
a bit
> > clearer in my mind, that you intend to return a copy on the stack if
you use
> > the second form.
> >
>
> First, I think you meant this:
> {{{
> return (SocketInfo(addr, port, sock, fallback));
> }}}
Yes that is what I meant.
>
> Secondly, I don't quite understand your point. In both cases the
SocketInfo structure is created on the stack - they are local variables.
The only difference is that in the latter case, we create an anonymous
variable which may be used in the point where it has been created and
immediately destroyed - doesn't live in the function scope like in the
former case. Before it is destroyed it is copied and returned. Same in the
former case: the variable is created, copied and destroyed. They are even
destroyed in the same time, because the function hits !''return!''
immediately after creation of the named variable.
>
> In addition, both versions produce exactly the same assembler code.
If the assembler code is no different than I don't suppose there is any
issue.
>
> >
-------------------------------------------------------------------------
> > pkt_filter_lpf.cc
> >
> > In receive(), you loop through reading the fallback socket:
> >
> > {{{
> > do {
> > datalen = recv(socket_info.fallbackfd_, raw_buf,
sizeof(raw_buf), 0);
> > } while (datalen >= 0);
> > }}}
> >
> > First, I think it should be > not >=.
> >
> > {{{
> > Upon successful completion, recv() shall return the length of the
message in bytes. If no messages are available to be received and the peer
has performed an orderly shutdown, recv() shall return 0. Otherwise, -1
shall be returned and errno set to indicate the error.
> > }}}
> > You should only try it again if it returns greater than zero.
>
> I was thinking that I should return on error, and 0 is not an indication
of error. But yes, there is rather no chance that I will get anymore data
from this socket if it returned 0. So I changed that as requested.
>
> >
> > Also, is there any chance we could get stuck here if something were
spewing
> > data at that socket? Should we consider some sort of throttle
mechanism?
>
> I was considering this issue. Ultimately, I decided not to implement it,
because I don't know if such a problem even has any chance to exist. If it
does, it can be a problem of any (not only fallback) socket we open. On
the other hand, during the normal operation both primary and fallback
socket should be in sync - they are configured to listen/filter the same
traffic. So, I really don't think it is a problem but I added a todo to
reconsider this design if needed.
>
I am good with this.
> >
> >
-------------------------------------------------------------------------
> > iface_mgr.h
> >
> > handleSocketConfigError
> > The brief description says "during operation on the socket". It is
not clear,
> > from the commentary that this handler is only for certain socket
operations.
> > I think it would be good to list the conditions under which it will be
invoked.
> > Certainly, it should state that it is not called during read, write,
or close
> > operations.
>
> Fixed.
>
> >
> >
-------------------------------------------------------------------------
> > iface_mgr.h
> >
> > openSockets4
> >
> > The parameter commentary for error_handler states that "the function
will
> > continue when the callback returns control.". It does not say what it
will
> > continue doing. There is no detailed discussion for what the function
does.
> > You should add a descriptive paragraph for the function. It should
perhaps
> > state the ramifications of the caller's handler doing something like
throwing.
>
> Added quite extensive description.
The description is very good.
>
> >
> >
-------------------------------------------------------------------------
> > iface_mgr_unittest.cc
> >
> > checkPacketFilterLPFSocket - It would help if this test had some
commentary
> > describing what it tests.
> >
>
> I added test description.
>
> > AT 1137, you have this:
> >
> > {{{
> > // Surprisingly we managed to open another socket. We have to
close it
> > // to prevent resource leak.
> > if (socket2 >= 0) {
> > close(socket2);
> > }
> > }}}
> >
> > Shouldn't this be a test failure? The whole intent is to not be able
to open
> > a second socket, shouldn't you do something like:
> > {{{
> > ADD_FAILURE() << "we opened two!" ?
> > }}}
>
> I added ADD_FAILURE but it doesn't change much. Note that the following
part of the test:
> {{{
> // The socket is open and bound. Another attempt to open socket and
> // bind to the same address and port should result in an exception.
> EXPECT_THROW(
> socket2 = iface_mgr2->openSocket(LOOPBACK, loAddr,
> DHCP4_SERVER_PORT + 10000),
> isc::dhcp::SocketConfigError
> );
>
> }}}
>
> already causes the test to fail if the socket opens. The other part is
simply to perform a cleanup after the test if it opens the socket for some
reason.
>
> >
> >
-------------------------------------------------------------------------
> > While not serious, running the unit the disabled tests as root with
valgrind,
> > it warns numerous times about attempting to close invalid file
descriptor.
> > Here's a snippet:
> >
> > {{{
> > ==17891== Warning: invalid file descriptor -1 in syscall close()
> > [ OK ] IfaceMgrTest.socket4 (5 ms)
> > [ RUN ] IfaceMgrTest.openSockets4
> > ==17891== Warning: invalid file descriptor -1 in syscall close()
> > ==17891== Warning: invalid file descriptor -1 in syscall close()
> > [ OK ] IfaceMgrTest.openSockets4 (13 ms)
> > [ RUN ] IfaceMgrTest.openSockets4IfaceDown
> > ==17891== Warning: invalid file descriptor -1 in syscall close()
> > [ OK ] IfaceMgrTest.openSockets4IfaceDown (8 ms)
> > [ RUN ] IfaceMgrTest.openSockets4IfaceInactive
> > ==17891== Warning: invalid file descriptor -1 in syscall close()
> > [ OK ] IfaceMgrTest.openSockets4IfaceInactive (9 ms)
> > [ RUN ] IfaceMgrTest.openSockets4NoErrorHandler
> > ==17891== Warning: invalid file descriptor -1 in syscall close()
> > ==17891== Warning: invalid file descriptor -1 in syscall close()
> > [ OK ] IfaceMgrTest.openSockets4NoErrorHandler (10 ms)
> > [ RUN ] IfaceMgrTest.openSocket4ErrorHandler
> > ==17891== Warning: invalid file descriptor -1 in syscall close()
> > ==17891== Warning: invalid file descriptor -1 in syscall close()
> > [ OK ] IfaceMgrTest.openSocket4ErrorHandler (9 ms)
> > }}}
> >
> > You should probably fix this.
>
> You deserve to take position in the QA team. :) Seriously, thanks for
that. I fixed it - the !IfaceMgr had a bug which caused the fallback
socket to be closed if its descriptor was non-zero (including negative
value).
>
Gee, thanks... I think....
> >
-------------------------------------------------------------------------
> >
> > The code passed cppcheck, and the unit tests were run under both OS-X
and Debian6.
> >
> >
>
> You really do deserve being in QA team ;)
>
>
You trying to get rid of me?
I do not need to see this ticket again.
--
Ticket URL: <http://bind10.isc.org/ticket/2765#comment:13>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list