![]() |
|
![]() |
| In our internal testing we are very close to Chrony with our synchronization performance, some of our testing data and an explanation of our algorithm is published in our repository: https://github.com/pendulum-project/ntpd-rs/tree/main/docs/a...
Given the amount of testing we (and other parties) have done, and given the strong theoretical foundation of our algorithm I’m pretty confident we’d do well in many production environments. If you do find any performance issues though, we’d love to hear about them! |
![]() |
| You might be doing too much work at the wrong level of abstraction. VMs should use host clock synchronization. It requires some work and coordination, but it eliminates the need for ntp in VMs entirely.
Hosts should then be synced using PTP or a proper NTP local stratum (just get a proper GNSS source for each DC if you have then funds). https://tsn.readthedocs.io/timesync.html Deploy chrony to bare metal servers wherever possible. |
![]() |
| Our project also includes a PTP implementation, statime (https://github.com/pendulum-project/statime/), that includes a Linux daemon. Our implementation should work as well or even better than what linuxptp does, but it's still early days. One thing to note though is that NTP can be made to be just as precise (if not more precise), given the right access to hardware (unfortunately most hardware that does timestamping only does so for PTP packets). The reason for this precision is simple: NTP can use multiple sources of time, whereas PTP by design only uses a single source. This gives NTP more information about the current time and thus allows it to more precisely estimate what the current time is. The thing with relying purely on GNSS is that those signals can be (and are in practice) disrupted relatively easily. This is why time synchronization over the internet makes sense, even for large data centers. And doing secure time synchronization over the internet is only practically possible using NTP/NTS at this time. But there is no one size fits all solution for time synchonization in general.
|
![]() |
| I agree that amplification and reflection definitely are worries, which is why we are working towards NTS becoming a default on the internet. NTS would prevent responses by a server from a spoofed packet and at the same time would make sure that NTP clients can finally start trusting their time instead of hoping that there are no malicious actors anywhere near them. You can read about it on our blog as well: https://tweedegolf.nl/en/blog/122/a-safe-internet-requires-s...
One thing to note about amplification: amplification has always been something that NTP developers have been especially sensitive to. I would say though that protocols like QUIC and DNS have far greater amplification risks. Meanwhile, our server implementation forces that responses can never be bigger than the requests that initiated them, meaning that no amplification is possible at all. Even if we would have allowed bigger responses, I cannot imagine NTP responses being much bigger than two or three times their related request. Meanwhile I've seen numbers for DNS all the way up to 180 times the request payload. As for your worries: I think being a little cautious keeps you alert and can prevent mistakes, but I also feel that we've gone out of our way to not do anything crazy and hopefully we will be a net positive in the end. I hope you do give us a try and let us know if you find anything suspicious. If you have any feedback we'd love to hear it! |
![]() |
| I'm afraid this is a pretty common sentiment. NTS has been out for several years already and is implemented in several implementations (including our ntpd-rs implementation, and others like chrony and ntpsec). Yet its usage is low and meanwhile the fully unsecured and easily spoofable NTP remains the default, in effect allowing anyone to manipulate your clock almost trivially (see our blog post about this: https://tweedegolf.nl/en/blog/121/hacking-time). Hopefully we can get NTS to the masses more quickly in the coming years and slowly start to decrease our dependency on unsigned NTP traffic, just as we did with unencrypted HTTP traffic.
|
![]() |
| I'm the person driving this.
NTP is worth moving to a memory safe language but of course it's not the single most critical thing in our entire stack to make memory safe. I don't think anyone is claiming that. It's simply the first component that got to production status, a good place to start. NTP is a component worth moving to a memory safe language because it's a widely used critical service on a network boundary. A quick Google for NTP vulnerabilities will show you that there are plenty of memory safety vulnerabilities lurking in C NTP implementations: https://www.cvedetails.com/vulnerability-list/vendor_id-2153... Some of these are severe, some aren't. It's only a matter of time though until another severe one pops up. I don't think any critical service on a network boundary should be written in C/C++, we know too much at this point to think that's a good idea. It will take a while to change that across the board though. If I had to pick the most important thing in the context of Let's Encrypt to move to a memory safe language it would be DNS. We have been investing heavily in Hickory DNS but it's not ready for production at Let's Encrypt yet (our usage of DNS is a bit more complex than the average use case). https://github.com/hickory-dns/hickory-dns Work is proceeding at a rapid pace and I expect Hickory DNS to be deployed at Let's Encrypt in 2025. |
![]() |
| What an interesting coincidence that all three of these accounts were created within 15 minutes of each other. I'm sure all "three" users are being "intellectually honest" here. |
![]() |
| How is C not memory safe? If I access memory I didn't allocate the OS shuts the program down. Is that not memory safety?
(Unless you're running it on bare metal ...) |
![]() |
| This is a good question to ask, especially in the age of everything pulling in every possible dependency just to get one library function or an `isNumeric()` convenience function.
The answer is that there is observability functionality which provides its results as JSON output via a UNIX socket[0]. As far as I can see, there's no other JSON functionality anywhere else in the code, so this is just to allow for easily querying (and parsing) the daemon's internal state. (I'm not convinced that JSON is the way to go here, but that's the answer to the question) [0] https://docs.ntpd-rs.pendulum-project.org/development/code-s... |
![]() |
| Hand rolled JSON input processing, yes. Hand rolled JSON output, no.
You're gonna have a hard time exploiting a text file output that happens to be JSON. |
![]() |
| Would you rather it had a JSON dependency to parse a config file, or yet another poorly thought out, ad-hoc homegrown config file format? |
![]() |
| I feel like using the incomprehensibly error-prone and inscrutable sudoers format as an example kinda argues against your point.
(I do agree that JSON is a terrible configuration file format, though.) |
![]() |
| On the contrary, I'm hosting a stratum 1 and 2 stratum 2s (at my previous company we offered 3 stratum 1s) on the ntp pool. It's useful, used, and still needed :-) |
![]() |
| The Jonestown massacre was actually grape flavor-aid:
https://www.vox.com/2015/5/23/8647095/kool-aid-jonestown-fla... They really do appear to be all in on avoiding memory leaks from C/CPP: > Over the next few years we plan to continue replacing C or C++ software with memory safe alternatives in the Let’s Encrypt infrastructure: OpenSSL and its derivatives with Rustls, our DNS software with Hickory, Nginx with River, and sudo with sudo-rs. Memory safety is just part of the overall security equation, but it’s an important part and we’re glad to be able to make these improvements. It seems like a really challenging endeavor, but I appreciate their desire to maintain uptime and a public service like they do. |
![]() |
| Golang's error handling is safer than C's, but it's more cumbersome than it needs to be. In high-level code, nearly every func you write can return an error, and 99% of the time you're just going to pass the error up. Webserver will catch all and send 4xx or 5xx, for example. Exceptions are a lot more convenient and encourage solid error handling.
Rust chose a good in-between (the "?" unwrapping syntax). In mid or low level code, anything can still fail, but I suspect the performance impact of supporting exceptions or similar for basic operations (integer overflow, div by 0, etc) wouldn't be worthwhile vs just crashing the program or doing something else. Interestingly, Rust doesn't crash in this case: https://doc.rust-lang.org/book/ch03-02-data-types.html |
![]() |
| Every now and then I think about forking Go and adding something like ?, and Pascal/Modula-2 like enumerations.
However then I realise, why bother, and go back into using C#, Java, D instead. |
![]() |
| The only thing I seriously plan to use Golang for is implementing a scripting language in my spare time. Its threading model (greenthreads flexibly mapped to OS threads) is attractive for that. |
![]() |
| Serious question: why does it need to change so much and so often? I know nothing about rust development, so I'm curious about why it's worlds different from the development of other toolchains. |
Particularly interested in the performance stats, how well the daemon keeps time in the face of various network problems. Chrony is very good at this. Some of the other NTP implementations (not on that chart) are so bad they shouldn't be used in production.