Network Time Foundation:
---+!! =ntpd= and Network Sockets Please offer comments, clarifications, and improvements. Here is the problem space: * We have a computer with some number of network interfaces and IPs * We want to run =ntpd= there in *any* supported configuration deemed useful by the admins * We want to come up with a configuration syntax that will direct =ntpd= to do one of the following for each IP: * open a socket for that IP and process packets * open a socket for that IP, read any received packets, and then drop them * do not open a socket for that IP Additional goals include: * have a generally useful default case * handle the simplest to the most complicated cases as simply, cleanly and clearly as possible * be able to report a spurious specification %TOC% --- --- ---++ Legacy In the past, =ntpd= has opened UDP port 123, sometimes on the wildcard port, and sometimes on each IP. With the inclusion of certain authentication mechanisms (autokey?) it became necessary to avoid the wildcard port and rely on specific ports. Unlike TCP, UDP is connectionless and this strategy is forced on us and is considered best practice. Firewalls require this as they look for the returned packet coming from the same address and port as the outgoing packet. For autokey reason has to do with matching the interface with the incoming (and outgoing) IP address for the security code. Time passed, and people noticed the large number of sockets =ntpd= was opening, and the =-L= option was implemented. The =-L= flag said "Ignore virtual IPs" and only worked on systems (Linux and Solaris) that embedded a =:= in the interface name; the code ignored (for some definition of _ignored_) those sockets. Harlan would be happy to see this code disappear, as it is not useful on all OSes. More time passed, and various folks wanted the ability to have =ntpd= limit the IPs it actually listened to. These efforts were distilled into the =-I= option, which now accepts both interface names and IPs. Early in this process, %MAINWEB%.DannyMayer had some significant talks with Rob Austein about security issues, and it was decided that there were Good Reasons (see [[#SecurityIssues][Security Issues]] for more information, and please add any missing items) that it is Better to open a socket for each IP on an interface, and depending on any =-I= options, we would either process the packet or "read and drop" the packet. Even more time passed, and several folks said "I don't want open-read-drop. If I provide a =-I= flag then I want =ntpd= to *only* open a socket for the specified interfaces and IPs." %MAINWEB%.HarlanStenn also had a chat with Rob Austein about this, and Rob said something like "Document the security issues and give them the power to make their own choice. They are consenting adults." --- --- #SecurityIssues ---++ Security Issues ---+++ open and process * packets sent to the bound IP addresses could be nefarious and depend on the security of the read loop and processing code ---+++ open-read-drop * prevents nefarious processes from opening UDP port 123, for receiving or sending NTP packets * prevents us from running monitor-only ( =noselect=) instances of =ntpd= on the same machine though there is nothing to prevent it using a single ntpd instance and specifying noselect on those it wants to monitor * depends on the security of the open-read-drop loop in handling nefarious packets * which can be expected to be more secure than reading the packet and looking at its contents --- Opening a connection on UDP port 123 needs root privileges (unix), or an Administrator account. If someone obtains root privileges, you have bigger security issues than someone launching a misconfigured ntp daemon. Policy of deny everything, accept selected is the default policy in every security-aware application that exists (example: djbdns, vsftpd, openbsd!) or at least an option is provided to tighten the listening ip/port (ssh,apache). Depending on the internal loop to handle bogus packets or forcing the user to configure some iptables rules to forbid traffic introduces another/a couple of points of failure in the time synchronization process. However, is more secure depending on a open-read-drop loop than on the inside reading-processing packet loop of ntpd. Nonetheless is far more secure not to receive the packet! -- %MAINWEB%.DiegoTorres - 22 Oct 2008 Diego, if =ntpd= opens the port and drops the packets, it also means that a nefarious program *cannot* do that. If the nefarious program does this to any ports before =ntpd= starts up, then =ntpd= can notice this and complain. While this may not be *your* preferred security model it is one that some people prefer, and again, until there is clear resolution on this point I want there to be a sufficiently robust mechanism in place to allow either of these security policy choices to be made. I believe what is being proposed will allow you to implement the security policy you want to use, and also allow somebody else to implement the other security policy. Do you disagree? -- %MAINWEB%.HarlanStenn - 31 Dec 2008 Harlan, the argument that a nefarious program *cannot* do that is severely flawed in several areas. Please note that IEEE 1003.1 specifies SO_REUSEADDR for rebinding addresses on protocols where this makes sense. I'm not sure if this has been standardized on a per protocol basis, but on a major platform such as Linux is the case for AF_INET protocols where sockets with the same sockaddr structure can be bound to multiple times provided that no one has called listen() on this socket. Note that this definition includes UDP sockets. The Linux kernel decides to which bound client to delegate incoming UDP packets on the aforementioned address to. This behaviour is normally to delegate it to one of the bound clients, and in all situations I have tested it seems to be to delegate the UDP packet to the client that bound to this address last of all. This means that on Linux I can easily bind() to the same address as ntpd is listening on *and* will get to see all traffic destined for that address as well while ntpd will not get to see it. This means that all the 'security policy' does in this case is give a false conception about security which does not exist. Diego his argument is also strong. To bind() to ports lower than 1024 you need to be root (for now assuming lack of a capability based security model), and being root there are countless ways in which I can abuse the ntp port for my own purposes, ranging from simply stopping ntpd to ptrace()ing the process and injecting code to have it close the descriptors for these ports so I can reopen them for my own purposes. Finally, please note that there *are* drawbacks of binding to every single IP address, which became apparant when running ntpd on a transparant proxy machine I am running which serves several thousands of IP addresses. The current method wastes a lot of memory for no reason at all, and forced me to reconfigure the rlimit for open descriptors in the ntpd process, as it bails out on the normal limit value with ENFILE. Of course everyone should be free to pick their own poison, but giving a false impression of security is far worse than giving the impression of having no security policy. -- Ronald Huizer - 30 Jan 2009 Ronald, this makes assumptions that are not true. We aggressively use SO_REUSEADDR to *not* allow other applications to reuse that address and we also bind and listen to the address on the NTP port. We certainly do not want more than one application to listen on a specific address/port since we need to ensure that when we send out a packet we need to ensure that the same application receives the resultant packet. This is crucial to the proper operation of NTP. If you gain root access to the system, not only can you do whatever you want, including disabling ntpd, there is nothing that cannot be done and you have more serious problems than worrying about ntpd, but we are not trying to address that issue. I must admit I am puzzled by the need to run 100's or even 1000's of IP addresses on one machine. It's a maintenance nightmare and I personally see no benefit to doing so, but that's not for me to worry about. One of our goals is to provide ways of giving what you need and not bind to all addresses in such cases with the caveat that you are on your own security-wise if it becomes a problem. -- %MAINWEB%.DannyMayer - 29 Mar 2009 Harlan and Danny: I strongly agree with Diego: It is not the task of an application to prevent users to run any kind of process on a machine. As Diego pointed out, in order to open the NTP port from a nefarious application requires root privileges on Unix and Administration privileges on Windows. Certainly other platforms offer similar protection algorithms against someone hijacking a server and IMHO these protection mechanisms are rightly handled by the underlying operating system. You cannot prevent someone from running a malicious piece of software (probably a modified build of ntpd) that opens UDP 123 after this bad guy used "killall ntpd" with the administrative rights he already possesses. I therefore cannot agree that opening the port on all interfaces will deliver any benefit security-wise. In my experience it is common practice and knowledge that you should only open the ports you are going to use. This will allow people to use their standard OS techniques to find out if there is a process listening to UDP/123 on an interface where there should be nothing. Nmap, netstat or other port scanners capable of finding open UDP ports, for example. In the light of this I would advocate to use one or more listen-on directives to enable specific interfaces and provide a "listen-on *" directive to enable listening on all interfaces (this could be the default). However, I am still not convinced about the requirement for a query-on directive. In my eyes this is a layer violation because the IP network stack and the routing core should be the place where it is decided which interface is used to reach a server. In the rare case that someone really wants to specify that a certain upstream server should be queried using a specific interface, I would recommend using "route add -host ..." to tell the OS which way it should take. Regarding the approach to ignore virtual IPs: This is another layer violation, you do not want to put in exemptions for each and every current and future type of interface. There are many good reasons to use virtual interfaces, one is adding VLAN support (which on Linux will create virtual interfaces like eth0.34) and if a customer decides to configure 100's of IP addresses on his machines and his OS supports this, it is IMHO not up to ntpd or any other layer 7 instance to decide that the user needs less than the OS-defined limit. -- %MAINWEB%.HeikoGerstung - 23 Apr 2009 Heiko, It is late and I am tired, so I may be missing something. I look at what you describe as a "policy decision" and I expect us to have a "mechanism" that will let folks like you and Diego implement that policy decision. There are other folks who disagree with you and who want the current behavior. I also expect our mechanism to be flexible enough to implement this policy as well. There are a bunch of scenarios below - can your idea about listen-on implement them? I have no idea about what you describe for query-on. As for virtual IPs, I think we're at another mechanism/policy decision. Where do you see that we are trying to trying to limit this? If folks want ntpd to open-read-drop on every IP on a box except for 1 or 2, that's fine. If they only choose to open 1 or 2, that's fine. I want our mechanism to be able to specify across this range of policy choices. Do you see a real problem with this? -- %MAINWEB%.HarlanStenn - 23 Apr 2009 --- ---+++ Not opening a socket * allows a nefarious program to open UDP port 123 on an IP/interface (but this program would require root privileges to do so on most platforms) * allows us to have other processes on the same machine open UDP port 123 on these other IPs/interfaces though this is currently not possible due to the requirement to use the localhost address for address resolution process. (OK, this last bit is an easily solved issue.) * packets for the unused IP addresses are never seen at all by =ntpd= . * uses fewer sockets. * uses fewer system resources to process packets * by far more secure (packet processing / DOS) * agrees with deny everything / accept needed security policy --- --- There are no real issues about not opening a socket, only benefits! Efforts should be done to provide the necessary configuration options to enable this behaviour, or at least, to let the user decide how he wants to manage his security. -- %MAINWEB%.DiegoTorres - 22 Oct 2008 Diego, I know several wizards who strongly disagree with you. Toward that end, unless and until there is a clear resolution on this matter, I want us to have "sufficient mechanism" to let people implement their "policy" choice. From what I can tell, this means we allow folks to choose between "don't open" and "open-read-drop" as they see fit. -- %MAINWEB%.HarlanStenn - 31 Dec 2008 Harlan, please quote the logical reasons these wizards presented. You do not contribute anything to the discussion by using arguments such as "I know several famous and bright people who all agree with me.". They can be wrong, you might cite them out of context, and so on. I do agree that in the end everyone should be free to make their own policy choices, which is certainly why there should be a method in ntpd for bind()ing sockets to a subset of addresses on a given system. -- %MAINWEB%.RonaldHuizer - 30 Jan 2009 There are serious consequences to not binding all interface addresses. To quote one example, if an ntpd server acting as a client sends out a packet and the remote server sends a response to that packet and a different application or just another instance of ntpd then the initiating app has lost the response and is unable to get a new estimate of time. The receiving application see that it is a response to a query and drops it on the floor as it didn't ask for the packet. Having more than one application or ntpd instance changing the clock is dangerous since each one will pull the clock back and forth. The results will be both unpredictable and unstable. This is the reason that ntpd or any other (s)ntp client should not be run on a virtual machine but only on the base O/S that runs the virtual machines. ntp is unlike any other daemon in that sense, only one should ever be run on any system. -- %MAINWEB%.DannyMayer - 29 Mar 2009 --- --- ---++ =ntp.conf= considerations For better or worse, we are trying to get to the point where we can completely control the configuration of ntpd using only the =ntp.conf= file. People have also requested the ability to specify the address that =ntpd= will use for its queries. ---++ Current Implementation (starting with 4.2.5p214) 4.2.5p212 introduces functionality in the form of new =interface= or =nic= directives which define a list of rules selecting, listen, open-read-drop, or don't listen for each interface. 4.2.5p214 changed from =192.168.0.0 prefixlen 16= to the more commonly seen =192.168.0.0/16=. A few examples: <verbatim> interface ignore all interface listen 192.168.0.0/16 nic drop eth1 </verbatim> The syntax is summarized the tarball html/miscopt.html#interface and one day may be published at udel.edu. The =-I= command line switch and the =nic= ntp.conf directive use the same rules. If any =-I= or =--interface= options are given on the command line, an implicit rule =nic ignore all= (note: should this be =nic drop all= instead?) is added first, then for each interface listed with =-I=, a listen rule is added. With the last matching rule winning, this preserves the existing semantics of =--interface=. =-I= rules are added before =ntp.conf= is processed. The =-L= command-line option ( =--novirtualips=) remains unchanged. If =-L= is enabled, interfaces with a colon in their name are ignored without consulting the other rules. =nic listen all= acts as a "flush" function in effect. While no rules are actually removed, the rule list search will always stop on an "all" entry. There is no negation of interface names or addresses implemented, but the same effect can be achieved with a pair of rules. For example, to listen on all interfaces except =eth0=: <verbatim> nic listen all nic ignore eth0 </verbatim> If you experiment with these directives, =ntpdc= has an =ifstats= command that is useful to verify which addresses are being used and how. -- %MAINWEB%.DaveHart - 15 Sep 2009 ---++ Implicit first rule In order to support the documented semantics of =-I= ( =--interface=) implemented in terms of the new rules, 4.2.5p212 in the presence of any =-I= or =--interface= command-line options first adds an implied rule equivalent to =interface ignore all=, then a rule for each =-I <name>= equivalent to =interface <name> listen=. Previously, ntpd implemented =--interface= by listening on every interface including those not used, but dropping input on all not listed after =--interface=, plus the localhost and wildcard addresses. At the same time, configure's support for --disable-listen-read-drop was removed. It was added to work around bug 1180 and was no longer needed with the change to not listen on non-listed interfaces, rather than listen-read-drop. Note that in 4.2.5212, there is no implicit first rule if there are any =interface= or =nic= directives. This was a surprise to Harlan, who expected a single =nic listen eth0= in ntp.conf to imply not using any other addresses. Harlan indicated to Dave Hart that was part of the plan, which was news to Dave and not in Danny's ntp-dev-listen2 repo upon which he based the implementation. In 4.2.5p212, to implement listening on a single interface (plus localhost and wildcard addresses, which are exempt from the rules), you must either use =--interface eth0=, or in ntp.conf list two rules, =interface ignore all= then =interface listen eth0=. This is because the default if no rule matches in =interface_action()= is to listen, which is useful when there are no =--interface= or =-I= command-line switches nor any =nic= or =interface= rules in ntp.conf. It would be straightfoward to change the implementation to use an implicit ignore or drop rule in the presence of any relevant switches or directives. This probably would have been fixed already but it brings up a somewhat contentious issue, ntpd's historical listen-read-drop behavior and its documentation. Since their introduction, =-I= alias =--interface= has claimed to limit which addresses ntpd listens on. In reality, the implementation has been to listen on every one and drop input on those not selected, plus localhost and wildcard addresses. Dave Hart believes ntpd should by default not listen to interfaces excluded by =--interface=, matching the longtime documentation and more importantly, the common expectations of system administrators familiar with other network service daemons. Harlan has expressed discomfort with changing the default behavior. Dave Hart believes if we are to revert to listen-read-drop as the implied default for =--interface= it should also be the implied default in the presence of any interface options or rules, but would prefer to see ignore (do not open) as the implied default. In order to maintain the effectiveness of the bug 1180 workaround, if the implicit first rule does become equivalent to =nic drop all=, configure's =--disable-listen-read-drop= needs to be reintroduced and control the implied first rule. Otherwise, those who successfully fixed 1180 once will have to fix it again by adding =nic ignore all= and =nic listen [name|address]= directives to ntp.conf to prevent ntpd from failing to start due to opening too many addresses. -- %MAINWEB%.DaveHart - 21 Sep 2009 --- ---+++ The =query-on= directive The =query-on= directive is now specified in a [[QueryOn][ Query-on configuration option page]] to make it more visible and has undergone some changes to reflect additional needs. Here are some examples: <verbatim> query-on 184.108.40.206 port 4123 query-on 220.127.116.11 query-on eth0 port any </verbatim> --- ---+++ The =interface= directive The current proposal is: <verbatim> interface [ listen | ignore | drop ] [ all | ipv4 | ipv6 | _iface_ | _address_ ] [ prefixlen _bits_ ] </verbatim> One can use =nic= as an alternative for =interface= . --- Danny's proposed syntax for this is now specified in a [[ListenOn][Listen-on configuration option page]] to make it more visible and has undergone some changes to reflect the discussions here and to add newly identified needs. The discussion however should continue here. The =listen-on= directive will take a list of IPs, netmasks and interfaces as its argument(s). It will also take =*= to mean "all IPs/interfaces", and allow for a negation operator. * would =*= be confused with the wildcard interface? * each =listen-on= directive would do a canonic "add" to the list * A better option would be =all= Should we allow DNS names in the list? * This would cause a processing delay until the name has been resolved * It would allow for additional flexibility in configuration Subsequent =listen-on= directives will append to the list of =listen-on= and command line =-I= options. --- ---++++ Listening The current mechanism for this is: <verbatim> interface listen [ all | ipv4 | ipv6 | _iface_ | _address_ ] [ prefixlen _bits_ ] </verbatim> ---++++ open-read-drop If we are not interested in processing packets for certain IPs/interfaces, we still need to specify if we want to open-read-drop or just not open the socket. The current proposal uses: <verbatim> interface drop [ all | ipv4 | ipv6 | _iface_ | _address_ ] [ prefixlen _bits_ ] </verbatim> ---+++++ drop via a =listen-on= operator Danny thinks that using a =noall= keyword should be sufficient - it would mean "any other IPs/interfaces should not be opened at all." He also proposes a =flush= keyword. If this is insufficient control, he suggests using the =^= symbol as the "drop" operator on the =listen-on= line. Harlan used to believe we would still want to use a negation operator as well to provide for both fine-grained control, and thinks additional keywords are problematic as they make it harder to allow for DNS name in directives (without using "uglier" keywords). (We are not currently supporting DNS names for the =interface= keyword.) --- The addition is a good thing since it will allow services to be more carefully tailored. However we would also want to do some form of policy controls so certain listen characteristics on Interfaces can be setup for read-only type services as well. So maybe "Listen _RW" as a replacement or an expansion of RESTRICT type controls. The other thing is that the IPV4 and IPV6 flags seem to be relative to the address specified in _address_ and not to Interfaces, so they should be grouped with the address to specify the type of address. The "ALL_ADDRESSES" type flag would mean all addresses obviously and the issue is then whether that means all v4 + v6 or whether it can be delimited. Also as to whether "NO" can be used to negatively set denial of the policy models you want to set that way but that's my take on making the policy easier to translate into a NTP configuration. interface listen [ all | ipv4 | ipv6 | _iface_ | _address_ ] [ prefixlen _bits_ ] In regard to OPEN AND DROP - isnt this the same process that the systems firewall would use? It seems to me like this is a replication of those controls and may cause some control loops which could be a larger problem. The current Open and Drop protocol control us un-needed in my opinion unless you want to be able to set specific control policies in addition to the system's firewall inside NTP. My take is that perhaps there should be a "restricted access" mode in which only Identified Systems can connect to this time-server. This policy control would prevent anyone from using the service who wasnt specifically authorized and this feature would become a key part of private time service network's use of NTP I am betting. Todd -- Users.ToddGlassey - 20 Sep 2009 %COMMENT% ---++++ ignore (ie, not open) The current proposal uses: <verbatim> interface ignore [ all | ipv4 | ipv6 | _iface_ | _address_ ] [ prefixlen _bits_ ] </verbatim> --- ---++ Other considerations ---+++ The _negation_ operator Harlan *thought* we must support a "negation" operator. This makes it easy to flush and reconfigure the =listen-on= mechanism using either nested =include= files in the =ntp.conf= file or using the =:config= directive from =ntpq=. Ideally, the negation operator will be * easy to read * easy to supply via =-I= (the shell) or =ntp.conf= We are currently considering using the exclamation point, =!=, as the negation operator. This is not particularly friendly to many shells, however. Note that BIND uses =!= for its negation operator in ACL's in named.conf so this should not be an issue. Update: the current syntax does not have a negation operator and seems to cleanly implement all of the use-case scenarios that looked like they originally needed a negation operator. ---+++ The =:config= directive of =ntpq= When we get commands via the =:config= directive, is there any reason to do anything other than treat them as an "append" operation? This has ramifications on the order in which we process directives. ---+++ Interface/IP directive processing and searching ---++++ Directive Processing Directives can come from the command line, the =ntp.conf= file (which may have =include= directives) or from runtime configuration directives. The order in which we process these directives may depend on the search order (described in the next section). As each argument for a directive is processed, we should "apply" it to the current data queue for that directive. This will, in effect, canonicalize the data, and also allow us to note if a subsequent directive either duplicates a previous directive or would never be processed because of a previous directive. An example of the latter would be Harlan's case of having separate queues for listen-on and drop-on, where the drop-on queue would only be checked if the IP was not caught by the listen-on queue. In this case, a =flush= directive would flush the queue. I would like to change this to be a separate directive =flushlist=: <verbatim> flushlist listen-on flustlist query-on flushlist dns </verbatim> These are deliberately separate directives since they are going to be used separately and have additional implications. These directives require that the interface list be scanned again since the existing lists have been obsoleted. However if there are new listen-on directives to be added after this, then the scan needs to wait until the entry of all new directives have been completed. The only way to ensure this is to have one more directive =rescan=, or perhaps =update=, which causes the interfaces to be rescanned and reset according to the new list. This is also true for the =flushlist query-on= directive. Note that all of this is only necessary if =ntpd= is already running and has completed reading it's configuration file. -- %MAINWEB%.DannyMayer - 11 May 2009 ---++++ Searching the directive queue I suspect we'll need a list of scenarios where given a list of IPs and interfaces, along with various goal states for what we listen to, what we open-read-drop, and what we do not open. Then we see how we get this behavior from the various implementation choices and how easy/understandable it is to specify this behavior. ---+++++ First Match Wins Danny has suggested using "first match wins" for searching the queue, along with "process =-I= directives first, then the =ntp.conf= file." ---+++++ Last Match Wins Harlan thinks we need "last match wins", processing the =ntp.conf= file first, then the =-I= directives. --- Last match wins complicates matters as the command-line interface needs to be processed first. -- %MAINWEB%.DannyMayer - 07 Jan 2008 The command line scanning happens Early, and collects information. It is a separate step to *process* that information. I don't see the complication you suggest exists - where/what is it? -- %MAINWEB%.HarlanStenn - 07 Jan 2008 While the command-line is processed early and collects information, it configures the server with the information provided immediately. The config file configuration comes later. the =listen-on= directive is the same as the =-I= directive and accomplishes the same task. So if we take your suggestion we would have to undo the configuration step done for the command line, configure from the config file and then add the command-line configuration back in. On top of that we then have to go through each and every address/interface specified every time instead of being done when a match is found with the interface. -- %MAINWEB%.DannyMayer - 08 Jan 2008 Danny, I don't see your point. It is trivial to process the config file and the command line options in any order we choose. In fact, any change to the configuration will *require* us to reprocess the existing interface and address lists. What do you mean by your last sentence? -- %MAINWEB%.HarlanStenn - 12 Apr 2008 Requiring "last match wins" seems especially true if =:config= directives append. Otherwise, it seems people would frequently need to flush and re-enter the entire set of directives. The alternative would be to number directive "chains" so people could add directives easier, and this is a level of effort that I'd prefer to avoid. -- %MAINWEB%.HarlanStenn - 23 Sep 2008 I think I have a way of doing this that makes sense and gives you last one wins and allows you to dynamically update the list and have the newer ones take precedence. There will be some issues dealing with adding query-on addresses that override existing query-on addresses since you would normally leave up the existing query-on addresses rather than tearing them down after one use. They might need to be torn down and reestablished after a configuration change. -- %MAINWEB%.DannyMayer - 29 Mar 2009 --- --- ---++ Scenarios If you have a scenario that is different, please add it. ---+++ Default case In the default case we open all IPs and listen to everything. ---++++ explicit coding: <verbatim> nic listen all </verbatim> --- ---+++ Virtual hosting In this case, the machine itself would be running =ntpd= and would have "many" virtual IPs. None of the virtual machines should be running ntpd which should be restricted to the underlying O/S which runs all of the virtual machines. ---++++ Network configuration * 18.104.22.168/23 on eth1 * 22.214.171.124 is the "base" machine IP * 126.96.36.199 - 188.8.131.52 are the virtual IPs on the machine ---++++ Listen on the "primary IP", open-read-drop the rest Currently, =-I 184.108.40.206= would have =ntpd= listen and process packets on 220.127.116.11, while all of the other virtual IPs would get open-read-drop behavior. With the current directives, we could avoid the command-line flag and use: <verbatim> nic listen 18.104.22.168 </verbatim> or avoiding implicit defaults: <verbatim> nic drop all nic listen 22.214.171.124 </verbatim> and assuming we continue to have open-read-drop as the default, that's all we'd need. ---++++ Listen on the "primary IP" and open none of the other IPs If we do *not* want to open any of the virtual IPs, we would use the following: <verbatim> # Danny's way listen-on all ignore listen-on 126.96.36.199 accept # or listen-on eth1 ignore listen-on 188.8.131.52 accept # current way nic ignore all nic listen 184.108.40.206 </verbatim> --- Experience running the =listen-on= directive without the 220.127.116.11/23 option on a machine with DHCP acquired addresses has shown that this is needed for most laptops and local office or home machines. <verbatim> listen-on all ignore listen-on 10.60.98.33 accept listen-on 10.10.10.101 accept listen-on fe80::a00:20ff:fed5:2220 accept listen-on if0 accept listen-on 10.10.10.111 drop listen-on ::1 accept listen-on 10.10.10.0/24 accept </verbatim> This will listen on and accept packets the 10.60.98.33 10.10.10.101 fe80::a00:20ff:fed5:2220 addresses as well as any addresses bound to the if0 interfaces but it will not listen on 10.10.10.111, will listen on ::1 (IPv6 localhost), not open sockets on non-specified addresses ( =all ignore=) and will listen on all addresses on the 10.10.10.0/24 subnet. -- %MAINWEB%.DannyMayer - 06 Jan 2008 I'm not sure what your point is here Danny. And your 10.10.10.101 is covered by the 10.10.10.0/24 spec, right? Under the current proposal your example above would be: <verbatim> nic ignore all nic listen 10.60.98.33 nic listen 10.10.10.101 nic listen fe80::a00:20ff:fed5:2220 nic listen if0 nic listen 10.10.10.0 prefixlen 24 </verbatim> (Under my first proposal =noall= is the default condition because of backward-compatibility issues.) -- %MAINWEB%.HarlanStenn - 03 Oct 2008 You don't want =noall= as the default condition as that would violate =the Principle of Least Astonishment=. Requiring people to add an explicit condition that they did not require before is unexpected and will break implementations everywhere. Furthermore we want to encourage better security and make changes that lessen security an explicit action. -- %MAINWEB%.DannyMayer - 29 Mar 2009 Danny, First, I don't see the POLA violation because we currently have *no* =listen-on= directive. If somebody specifies even 1 =listen-on= directive, they are saying "I want to use =listen-on= semantics" and we can make the default choices anything we want. Therefore your second sentence about requiring people to add an explicit condition "that they did not require before" is, IMO, misleading and a red-herring. Finally, your third/last sentence takes a blanket position on security policy and there are people who think the current behavior is *more secure* than what you propose. Let's stay out of the policy debate for now and focus on mechanism. -- %MAINWEB%.HarlanStenn - 26 Apr 2009 --- --- ---+++ One public network interface, one private network interface ---++++ Network configuration * eth0: public interface, accept NTP traffic on 18.104.22.168 * eth1: private interface, many virtual IPs, do internal NTP traffic on 22.214.171.124 ---++++ open-read-drop on public, only open on 1 internal IP on the private network This is based on the new syntax defined in the [[ListenOn][Listen-on page]] <verbatim> # Danny's latest way listen-on eth0 drop listen-on 126.96.36.199 accept listen-on eth1 ignore listen-on 188.8.131.52 accept </verbatim> -- %MAINWEB%.DannyMayer - 27 Apr 2009 This provides precise syntax on what you want to accomplish. The order is last one wins. This should be read from the bottom up as the order is important as follows: if 184.108.40.206 exists open, accept and process packets received otherwise if eth1 exists don't open sockets on any address on eth1. otherwise if 220.127.116.11 exists open, accept and process packets received otherise if eth0 exists open, accept and drop packets on all addresses on this interface. -- %MAINWEB%.DannyMayer - 30 Mar 2009 <verbatim> # current way nic drop eth0 nic listen 18.104.22.168 nic ignore eth1 nic listen 22.214.171.124 # or nic drop eth0 nic ignore eth1 nic listen 126.96.36.199 nic listen 188.8.131.52 </verbatim> --- ---++ Other related items ---+++ What about the wildcard socket? Under exactly what conditions (this could well be OS-dependent) is it needed? --- Currently, the wildcard socket is open but always dropping packets. There may be special considerations that need to be addressed here but still need to be thought through. Adding a =nowild= option to listen-on could be added so that it doesn't try and open the wildcard addresses: <verbatim> listen-on wild ignore </verbatim> is one possibility. Note that normally =ntpd= should *not* be accepting packets on the wildcard addresses since there are a number of problems if you do so including sending return packets on a different address from the sender's requested address. -- %MAINWEB%.DannyMayer - 27 Apr 2009 Danny, *why* is the wildcard socket being opened? Why do we need to give the user the option of (not) opening the wildcard socket? -- %MAINWEB%.HarlanStenn - 06 Jan 2008 The question of opening the wildcard sockets is an open one. If you are opening sockets on all addresses then you need to include the wildcard sockets. If you don't include the wildcard addresses is there a downside? There used to be a number of special cases where the wildcard addresses were needed. I think but I am not sure that it is no longer needed. -- %MAINWEB%.DannyMayer - 07 Jan 2008 *Why* do we need to include the wildcard socket if we are opening sockets on all addresses? If there are still special cases where a wildcard address is needed, we need to have that information documented. We can always stop opening it and see who hollers. -- %MAINWEB%.HarlanStenn - 07 Jan 2008 There was a requirement at one time. I think it's no longer there but it would take time to figure out if there's still a reason for it. If you are going to suggest doing/not doing something and see who hollers, why not make my implementation available and see who hollers? You have stated that you want to work everything out first so why not this too? -- %MAINWEB%.DannyMayer - 08 Jan 2008 Disabling wildcard will not cause backward incompatible problems. It will be OK or it won't, and if it is not OK we will hear about it and fix it. I do not intend to release code that has a good chance of being backward-incompatible. Let's come up with a complete spec, get feedback from people, implement what we need now (perhaps implementing other bits down the road a bit), and then roll it out. -- %MAINWEB%.HarlanStenn - 08 Jan 2008 The wildcard socket is not the same as all individual addresses. -- %MAINWEB%.DannyMayer - 29 Mar 2009 Listening on wild is nice in case someone adds an interface after ntpd starts. -- Users.MortyAbzug - 2010-05-06 --- ---+++ What about 127.0.0.1 and ::1? Right now, we always open a socket for 127.0.0.1 and ::1, because that is the "default" address that =ntpq= will query, and that is where the forked resolver process will send its answers. Harlan can foresee a use for running multiple =ntpd= processes on a machine, where at most one =ntpd= is controlling the system clock and any other =ntpd= processes are in monitor-only mode. He grants this would probably be a rare-use case, mostly for testing purposes. But in this case, we would not be able to have more than one of these =ntpd= processes bind to either 127.0.0.1 or ::1. In these cases, one could easily supply =ntpq= with an IP, or =ntpd= could open a socket to another port on 127.0.0.1, ::1, or use a different (virtual?) IP for communication with the forked resolver process. --- ntpq should be available for use to query the status of the local ntp server and it requires the localhost addresses. It's hard to see not being able to do that for the local server. -- %MAINWEB%.DannyMayer - 29 Mar 2009 ---+++ Why not use ephemeral ports for client connections, and port 123 only for the server? I propose two modes of handling sockets in ntpd: 1 When ntpd is acting as a server (i.e. responding to queries from clients), it may respond to the client from the ip/port where it received the query (generally port 123 on some local interface). 1 When ntpd is acting as a client (i.e. initiating queries to other ntpd servers), it must use a separate socket, specifically allocated for communication with that server, using the =connect(2)= system call to bind the socket to an ephemeral port. Do not call =bind(2)= on this socket at all. This will allow the network stack to "do the right thing" with respect to routing. This is exactly what BIND does in modern versions of named, and it generally works well with stateful inspection firewalls. I think if you go with this approach, you don't need to deal with all the complicated logic around =query-on=, =drop-on=, etc. All you need to do is the =listen-on= directive, and do not open sockets for interfaces not listed in it. The only question I'm unsure of is whether this behavior would conform to relevant RFCs. But note that =ntpdate -u= already implements similar behavior, and the ntpd code doesn't seem to mind responding to queries from unprivileged ports. So I think it should probably work just fine. -- %MAINWEB%.MichaelGlasgow - 25 Aug 2008 Ephemeral ports are a pain to handle and I know only too well how BIND works. In the case of NTP you do not want it to work the same way that BIND does, since the ntpd code creates associations with the local and remote addresses and all of this gets caught up in issues with autokey authentication. You *do* normally need to bind to all addresses on the system on port 123/UDP and you are required by protocol to listen for incoming packets on port 123/UDP. I have just added a port option to the query-on directive to deal with the need to sometimes specify the sending query port number. -- %MAINWEB%.DannyMayer - 31 Dec 2008
This topic: Dev
Topic revision: r42 - 2022-09-07 - 16:43:41 -
Copyright &© 1999-2022 by the contributing authors. All material on this collaboration platform is the property of the contributing authors. Ideas, requests, problems regarding the site?