The main problem is the wrong handling of UTC by NTP and Unix.
NTP is simply on the wrong time system. It is a system which is designed to accurately keep a monotonous steady time shared among millions of systems spread across time zones. It does not have any sensible way of dealing with the fact that some systems want to suddenly add a second or subtract one, just like it cannot deal with time zones or Mayan calendars. Those are simply outside its problem domain. Luckily the fix is simple: Stop handling leap seconds at all in NTP, just keep counting seconds. If you must handle it in NTP for those client systems too primitive to do it themselves, do it by transmitting the current offset between NTP time and UTC. The best solution would be to define NTP time to be TAI of course, but it will likely have to be TAI+offset to handle backwards compatibility.
Unix again does it wrong by keeping system time in UTC rather than TAI. UTC is useful for humans but difficult for machines, it should be handled by the human interface libraries, just like time zones. Kernel time should be TAI of course. When leap seconds are inserted, systems must be updated, but that is not particularly harder than keeping the time zone files up-to-date is already. Of course it would be a lot easier if the astronomers would let us know a few years in advance rather than six months, but then the offset between TAI and UTC could exceed 0.9 seconds, and as we all know that would bring Ragnarok.
GNU systems even have sets of time zones for precisely this reason: "POSIX" and "Right". Unfortunately it is not possible to use the "Right" time zones with current NTP.