Using Proper NTP on Android Phone

Illustration

As a time connoisseur, I really get really pissed off when my phone’s time is off by a second or two. Considering phone receives time from the radio network, one would expect this not to happen. However, for some reason, it seems no USA network provider actually cares to have their radio time straight. The solution to this problem would be using an NTP server instead of the time provided by the network. However, with an Android devices that’s not as straightforward as one would expect. But it is possible…

Before starting anything, we first need to turn on Developer Options (usually tapping Build Number 7 times). Once this is enabled, we need to enable USB Debugging (Settings > System > Advanced > Developer Options > USB debugging). With this done, we can finally download Platform Tools and check if our device is visible:

adb devices
 List of devices attached
 0A281JCCBA0317  device

Once connectivity is tested, we can immediately go onto setting the NTP server followed by a reboot:

adb shell settings put global ntp_server ^^time.medo64.com^^
adb reboot

Once device has rebooted we can check the value:

adb shell settings get global ntp_server 
 time.medo64.com

And that’s it. Now your device will use the defined time server instead of the unreliable network time.

Getting IPv6 Going on RouterOS 7.1

I already did a post about IPv6 on Mikrotik but with RouterOS 7 going out, some things have slightly changed. So, it’s time for an updated guide. And, as one might expect, things are pretty much the same.

As before, prerequisite is that you get at least /64 prefix from your ISP (Comcast in my case) via DHCPv6. Also assumed is empty IPv6 configuration.

The first thing I like doing is disabling the default neighbor discovery interface. Blasting IPv6 router advertisements on all interfaces is not necessarily a good idea:

/ipv6 nd
set [ find default=yes ] disabled=yes

The next step is to setup DHCP client. Within a few seconds, you should see the prefix being allocated:

/ipv6 dhcp-client
add add-default-route=yes interface=ether1 pool-name=^^general-pool6^^ request=prefix  use-peer-dns=no

:delay 5s
print
 Flags: D - dynamic, X - disabled, I - invalid
  #    INTERFACE             STATUS        REQUEST             PREFIX
  0    ether1                bound         prefix              ^^2601:db8:9780:ee2c::/64^^, 3d14h41m41s

At this time I love to allocate address ending with ::1 to the router itself:

/ipv6 address
add address=::1 from-pool=^^general-pool6^^ interface=^^bridge1^^ advertise=yes

Now it should be possible to ping its address from external computer (in this example address would be 2601:db8:9780:ee2c::1). If this doesn’t work, do check if you have link-local addresses. If none are present, reboot the router and they will be regenerated.

With router reachable, it is time to delegate IPv6 prefix to internal machines too. For this purpose, setup RA (router announcement) over the bridge. While default interval settings are just fine, I like to make them a bit shorter (20-60 seconds):

/ipv6 nd
add interface=^^bridge1^^ ra-interval=20s-60s

And that’s all. Now your computers behind the router will have direct IPv6 route to the Internet. Do not forget to setup both router firewall and firewall of individual devices. There is no NAT to save your butt here.

PS: Here is the basic IPv6 firewall allowing all connections out while allowing only established back in:

/ipv6 firewall filter

add chain=input action=drop connection-state=invalid comment="Drop invalid"
add chain=input action=accept connection-state=established,related comment="Accept established"
add chain=input action=accept in-interface=ether1 protocol=udp src-port=547 limit=10,20:packet
add chain=input action=drop in-interface=ether1 protocol=udp src-port=547 comment="Drop ext DHCP >10/sec"
add chain=input action=accept in-interface=ether1 protocol=icmpv6 limit=10,20:packet
add chain=input action=drop in-interface=ether1 protocol=icmpv6 comment="Drop ext ICMP >10/sec"
add chain=input action=accept in-interface=!ether1 protocol=icmpv6 comment="Accept internal ICMP"
add chain=input action=drop in-interface=ether1 comment="Drop external"
add chain=input action=reject comment="Reject everything else"

add chain=output action=accept comment="Accept all"

add chain=forward action=drop connection-state=invalid comment="Drop invalid"
add chain=forward action=accept connection-state=established,related comment="Accept established"
add chain=forward action=accept in-interface=ether1 protocol=icmpv6 limit=20,50:packet"
add chain=forward action=drop in-interface=ether1 protocol=icmpv6 comment="Drop ext ICMP >20/sec"
add chain=forward action=accept in-interface=!ether1 comment="Accept internal"
add chain=forward action=accept out-interface=ether1 comment="Accept outgoing"
add chain=forward action=drop in-interface=ether1 comment="Drop external"
add chain=forward action=reject comment="Reject everything else"

Local WAN Redirect on Mikrotik

As a keeper of the family Minecraft server, I had the holy duty of setting up the firewall to accept it from the outside. External DNS was as easy as CNAME toward the router cloud name. Sorting out redirects was equally uneventful. Just poke a few holes in the firewall so it plays nice with NAT and you’re essentially done:

/ip firewall filter
add action=accept chain=input protocol=tcp dst-port=25565 \
    comment="Accept Minecraft"
add action=accept chain=forward in-interface=ether1 protocol=tcp dst-port=25565 \
    comment="Accept Minecraft (Internet)"

/ip firewall nat
add action=dst-nat chain=dstnat in-interface=ether1 protocol=tcp dst-port=25565 \
    to-addresses=192.168.1.4 to-ports=25565 comment="Minecraft WAN Redirect" 

In order to access it from the internal network, I just added entry in my DNS server with the local address and life was good.

However, with the move toward encrypted DNS, my Mikrotik wasn’t the main source of truth anymore. Suddenly computers on my network would receive external IP and my router didn’t know how to route that. Since routing is one of its duties, you can see why I would have a problem with this.

Most solutions I’ve seen dealt with hairpin NAT but one didn’t. And my solution was essentially the same:

/ip firewall address-list
add address=10.0.0.0/8 list=local-list
add address=172.16.0.0/12 list=local-list
add address=192.168.0.0/16 list=local-list

/ip firewall nat
add action=dst-nat chain=dstnat protocol=tcp dst-port=25565 \
    dst-address-list=!local-list dst-address-type=local \
    to-addresses=192.168.1.4 to-ports=25565 comment="Minecraft Local WAN Redirect" 

This essentially says to redirect any address local to router (and WAN address is present on router even in DHCP case) but not present in the list of local addresses (i.e. globally routable) to our internal IP and port. As simple as it gets.

UDP OpenVPN on Mikrotik 7

Illustration

Despite UDP being ubiquitous on pretty much any other OpenVPN platform, for a long while Mikrotik only supported TCP variant. With Mikrotik RouterOS 7 finally being released earlier this year, we at last got an UDP support for OpenVPN.

For some people UDP/TCP difference might not matter much. If you have a stable connection chances are you really don’t need to care - OpenVPN via TCP will serve you without any issues.

But, if you are dealing with multiple connections over a high latency and/or lossy network, UDP will be much faster as lost packets for one connection will not impact the other. How big the difference is? Well, I have a connection between USA and Croatia and it leaks like a sieve. My speed went from about 400 Kbps to 1000 Kbps just due to this change (tested using 2 parallel connections). I would say switching to UDP was well worth the effort for my use case.

Getting UDP enabled for OpenVPN server once you get Mikrotik 7.1 or higher running is trivial assuming you have OpenVPN via TCP already configured. You just change Protocol value to udp, update your client side with the same change (albeit for proto field) and you’re done.

But, in the interest of completeness, let’s see how one would create such config from scratch.

First we create all the certificate templates (give it at least 10 years validity):

/certificate
add name=ca-template common-name=^^example.com^^ days-valid=3650 \
  key-size=2048 key-usage=crl-sign,key-cert-sign
add name=server-template common-name=^^*.example.com^^ days-valid=3650 \
  key-size=2048 key-usage=digital-signature,key-encipherment,tls-server
add name=client-template common-name=^^client.example.com^^ days-valid=3650 \
  key-size=2048 key-usage=tls-client

As far as OpenVPN server is concerned, you can use whatever you want for certificate’s common name. Since some other VPNs are not as forgiving (yes SSTP, I am looking at you), I made it a habit to use either external IP or the host name here.

Once we have templates sorted out, we can do the signing:

/certificate
sign ca-template name=ca-certificate
sign server-template name=server-certificate ca=ca-certificate
sign client-template name=client-certificate ca=ca-certificate

And then exporting certificate material:

/certificate
export-certificate ca-certificate export-passphrase=""
export-certificate client-certificate export-passphrase=^^12345678^^

This should give you three files: cert_export_ca-certificate.crt, cert_export_client-certificate.crt, and cert_export_client-certificate.key. After copying these files to the computer for later I like to rename them to ca.crt, client.crt, and client.key respectively. It just makes everything a bit tidier.

Next we need a separate pool of IP addresses for clients. I will assume you have your clients in some other network (e.g. 192.168.1.x) and this new network is just for VPN:

/ip
pool add name="vpn-pool" ranges=192.168.8.10-192.168.8.99

Instead of editing the default encrypted profile, we can create a new one. If you use different DNS server, do change it here, and while at it, you should really use a bit more imaginative user/password pair:

/ppp
profile add name="vpn-profile" use-encryption=yes idle-timeout=10m \
  local-address=192.168.8.250 dns-server=1.1.1.1 remote-address=vpn-pool \
  secret add name=^^user^^ profile=vpn-profile password=^^password^^

Finally, we can enable OpenVPN server interface:

/interface ovpn-server server
  set default-profile=vpn-profile certificate=server-certificate require-client-certificate=yes \
  auth=sha1 cipher=aes128,aes192,aes256 enabled=yes protocol=udp

Assuming you’re using Windows, you can copy both ca.crt and client.crt to C:\Program Files\OpenVPN\config\ directory alongside client.ovpn. On Linux, one would do the same, just in the /etc/openvpn/client directory.

You don’t have client.ovpn? Well, one is in sample-config directory and we just need to change/add the highlighted items. And since we’re finally using UDP, we can leave proto as it is.

client
dev tun
proto udp
remote ^^example.com^^ 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client.crt
key client.key
remote-cert-tls server
cipher AES-128-CBC
auth SHA1
auth-user-pass
redirect-gateway def1
verb 3

A bit annoying step is being asked for the private key passphrase (in the addition to the username/password pair). Mikrotik doesn’t allow export without it but fortunately we can use OpenSSL to change that:

openssl.exe rsa -in client.key -out client.key
 Enter pass phrase for client.key: 12345678
 writing RSA key

With this, your VPN connection should work like a charm.

PS: Do not forget to adjust firewall if necessary (TCP port 1194).

/ip firewall filter
add chain=input protocol=udp dst-port=1194 action=accept place-before=0 comment="Allow OpenVPN"

AddSeconds for TimeOnly

One really annoying fact of life you get when dealing with TimeOnly is that class has no AddSeconds method (AddMilliseconds or AddTicks either). But adding that missing functionality is not that hard - enter extension method.

While TimeOnly has no direct methods to add anything below a minute resolution, it does allow for creating a new instance using 100 ns ticks. So we might as well use it.

public static class TimeOnlyExtensions
{
    public static TimeOnly AddSeconds(this TimeOnly time, double seconds)
    {
        var ticks = (long)(seconds * 10000000 + (seconds >= 0 ? 0.5 : -0.5));
        return AddTicks(time, ticks);
    }

    public static TimeOnly AddMilliseconds(this TimeOnly time, int milliseconds)
    {
        var ticks = (long)(milliseconds * 10000 + (milliseconds >= 0 ? 0.5 : -0.5));
        return AddTicks(time, ticks);
    }

    public static TimeOnly AddTicks(this TimeOnly time, long ticks)
    {
        return new TimeOnly(time.Ticks + ticks);
    }
}

With one simple using static TimeOnlyExtensions; we get to correct this oversight. Hopefully this won’t be needed in the future. While easy enough, it’s annoying that such obvious methods are missing.