Limiting port 8089 access for remote viewing when using linux for channels dvr

As most people know you have to open port 8089 to the world for remote viewing. Per some topics some people (along with myself) are concerned about having that port open to the world and all the scanning that happens to that port when it's open to the world. You can run a VPN to help resolve/mitigate this issue (I run OpenVPN instead of Tailscale) but when you're using a stick like Chromecast or Firestick you have issues running a VPN on them. I know there are some backdoors to trying to run a VPN on sticks and unless things have changed the vendors are constantly messing with things that make it difficult. So to limit my exposure I looked into the IP addresses that were being used to deliver the remote content. It seems all the addresses that remote viewing was using were AWS EC2 addresses. So after testing this for multiple days it seems remote viewing is working fine when I enable it and allow all AWS EC2 subnets into my server.

So for anyone that is interested here is the script I use to gather the AWS EC2 subnets and create an nftables "set" file that I can load into nftables when I want to remotely stream when a VPN isn't an option. If you're using an older version of linux that uses iptables then you can easily modify the script to create an ipset.

To use that "set" you need the following 2 rules in your main nftables file. First you need to import that "set" file after you define your filter table in your main nftables file using the following line: NOTE: my file is called channels_dvr.set but you can call it whatever you want.

include "/etc/nftables/channels_dvr.set"

Now that the "set" is imported you can now enable the following filter rule whenever you want to turn on remote viewing: NOTE: Change "inet filter NFT-INPUT" to whatever your filter type/chain name you use.

# Allow remote access to Channels DVR
add rule inet filter NFT-INPUT ip saddr @CHANNELS_DVRv4 tcp dport 8089 counter accept

Here is the perl script I use to create the set file that you copy to the /etc/nftables directory. I usually place the file in my home directory but the script below places it in /tmp. Also, in the "Write last lines" section change the IP address to the private local address of your internet router since some traffic will come from that. To make things easier per the way amazon presents the file I use curl instead of per modules for the download. Also, yes I can check the download status and add more logic but I look at the file that gets created and know whether there was an issue or not.

> cat get_amazon_ec2_addresses
#!/usr/bin/perl
#
# This script downloads the Amazon AWS ip-ranges.json file which contains
# all its IP address ranges.  It then extracts all the EC2 addresses from
# the file and places them in the firewall to allow port 8089 for
# Channel DVR's remote DVR service.

# Include any necessary modules
use lib qw(..);
use JSON qw( );

# Initialize misc variables
$channels_dvr_set_file = "/tmp/channels_dvr.set";
$ip_ranges_file_url = "https://ip-ranges.amazonaws.com/ip-ranges.json";
$ip_ranges_file = "/tmp/channels_dvr.set";
$temp_file = "/tmp/ip-ranges.json.tmp";

# Make sure the channels dvr nftables set file exists and has the
# correct permissions.
open (CDVR, ">>$channels_dvr_set_file") || die "Can NOT open for write the channels dvr nftables set file $channels_dvr_set_file $! : ABORTING...";
close (CDVR);
chmod 0755, $channels_dvr_set_file;

# Download the Amazon AWS ip-ranges.json file
$download_status = `/usr/bin/curl -o $temp_file $ip_ranges_file_url > /dev/null 2>&1`;

open (AWSIPS, ">$ip_ranges_file") || die "Can NOT open for write the new IP Ranges file $ip_ranges_file $! : ABORTING...";

# Write first lines of new Amazon AWS IP ranges set file
print AWSIPS "#!/usr/sbin/nft -f\n";
print AWSIPS "\n";
print AWSIPS "add set inet filter CHANNELS_DVRv4 { type ipv4_addr; flags interval; }\n";
print AWSIPS "\n";
print AWSIPS "add element inet filter CHANNELS_DVRv4 {\n";

$json_text = do {
  open ($json_fh, "<:encoding(UTF-8)", $temp_file) || die "Can NOT open for read the temporary Amazon AWS IP ranges file $temp_file: $!\n";
  local $/;
  <$json_fh>
};

$json = JSON->new;
$data = $json->decode($json_text);

for (@{$data->{prefixes}}) {
  if ($_->{service} eq "EC2") {
    print AWSIPS $_->{ip_prefix}.",\n";
  }
}

# Write last lines of new Amazon AWS IP ranges set file
print AWSIPS "192.168.x.x/32\n";
print AWSIPS "}\n";

close (AWSIPS);
exit (0);

Hopefully the above script will help others using linux and want to limit their exposure when wanting to enable remote viewing.

There's no proxying between you and your clients when you are connecting remotely.

You setup port forwarding on your router, we handle dynamic DNS, and your clients use that dynamic DNS to connect directly to your router.

If you block IPs from accessing port 8089, you are blocking your clients from accessing your DVR.

Hi Eric,

Sigh OK. So the EC2 addresses are just your servers doing dynamic DNS so that connection needs to initially be made. But, when that connection is made then all traffic then comes from the internal router's IP address and not the remote address like I thought.

I saw many remote IPs hitting my linux server when I opened up 8089 to the world. I need to do more research on why I was seeing outside addresses hitting that port that were not EC2 addresses and they were not related to channels dvr.

I'm definitely missing a piece here. Since my topic isn't correct should I remove it or did you want to remove it?

Thanks for the additional info.

Hey Eric,

@eric To help me out. Why when you're doing dynamic DNS the traffic is coming from the AWS EC2 servers. But, when the chromecast Cdvr client is doing the remote DVR function the traffic is originating from my router's internal IP address and not it's remote public IP address.

That would help me understand what is going on.

Thanks again for your help.

@eric, I may have the answer, since the Chromecast is still on my internal network and it's essentially trying to reach the public address on my router then my router is most likely doing SNAT so it can speak to my internal ChannelsDVR server. That is probably what is going on and I would need to test with my Chromecast outside my internal network.

If that is the case then along with my script above I would also need to allow the public IP address the Chromecast is on when I'm outside my home.

That'll teach me for not testing when outside my home!

Thanks again for the info.

The Dynamic DNS is configured by your DVR sending an update to our servers every 4 hours with the latest IP.

The request you are seeing from EC2 is a courtesy check we do on our cloud infrastructure to tell the user if the DVR is likely reachable or not (otherwise they will see the browser spinning for minutes until finally timing out, which is not a good user experience).

There are lots of things scanning on the internet. There's not a lot that you can do about it, but the Channels DVR Server provides the authentication to make sure that none of those requests actually do anything harmful.

This is called "Hairpin NAT", where the router is doing something special when it sees an internal IP is trying to access its external IP. Without special treatment, those connections will just timeout.

Thanks @eric for all the additional info.

I do understand that there is constant scanning going on and to help mitigate any possible vulnerabilities with software I try to lock down port access as much as possible to accomplish some kind of defense in depth. I understand that your software requires auth and uses ssl but as a sysadmin my job is to try to limit exposure just in case there are any current or future defects in coding that may allow any kind of compromise. I do understand you and your team do an excellent job. It's more of belt/suspenders with me.

I'm used to working with loadbalancers in which you need to occasionally do SNAT when servers inside the loadbalancer's network need to speak to other services inside the same loadbalancer network. I must admit I'm not used to the term Hairpin Nat but it looks like it's what's referred to for home routers while SNAT is the term we use for enterprise networks. Thanks for letting me know about the Hairpin terminology. Learn something new everyday. :slight_smile:

So now with your information I'll most likely create a specific url that I can access remotely that will add that specific IP to the running firewall which will allow port 8089 access from that specific IP.

Thanks again for all your time and help with this! I just love learning more about Channels since I'm now using it heavily and will help me build a stable service.

Good luck. If you're really concerned about it being publicly accessible, it sounds like it could be worth your effort to get Tailscale or OpenVPN running on your streaming devices. The Tailscale support on the Apple TV is really great, though I know it isn't quite as smooth on the Fire TV/Android platforms.

Thanks @eric. When I was researching Tailscale it seemed people were having issues with Android sticks (Fire TV/Chromecast) since I don't have Apple TV. They'd get it to work then the next stick upgrade or two it would break. I already run OpenVPN on my servers/workstations so I may try that to see how well that works. I have the time to work on it so I may go in that direction.

Thanks again.

Just to add my 2 cents here. I have never used the built in remote access, or even tailscale. Never wanted to do port forward just for Channels DVR.

Instead, i have a self hosted Wireguard VPN (via Pi-VPN) that i connected my remote device to, and that allows me access to my local Channels DVR and Plex. There is a port forward required to the VPN server, but since it points to a isolated VM system, I am not concerned with it being scanned or "hacked".

You can set a restriction in your router for a port forward to limit it to a whitelist of IP's allowed to connect to the port, however, that only would be workable if you remote connection always uses the same ip to connect. For stationary remote client, with home internet, most likely external IP not often to change. However, a 5G cellular connection, is almost always dynamic ip.

Wireguard is much better as has much less overhead than OpenVPN.

Thanks for the info @speedingcheetah. It's interesting seeing other methods people are using. As you said WireGuard is faster than OpenVPN. Since OpenVPN was developed/released so long ago on many platforms I invested in it that a long time ago so run it everywhere. Although, I can easily run both since I have a lot of bandwidth/resources on my server(s). I also have a cloud based vhost with a static IP so I use that for a lot of my access along with watching Channels when not using a stick.

Thee are plenty of YT vids or other articles comparing the 2 VPN's... far as i had researched, and in my personal experience, Wireguard is usually much faster.
I think Tailscale uses Wireguard as their underlying connection type.

I got one of those travel routers with built in client vpn.

1 Like

Thanks for the additional info.

Thanks @Edwin_Perez. That's definitely an easy option with a small upfront expense for the travel router. The computer geek in me always tries using the hardware I currently have to make things work. But, as we all know, time is money so your method may be cheaper in the long run but not as fun. :slight_smile:

Yeah great investment also tethers to my phone ... I got this one GL.iNet GL-MT3000

Does this work for IPV6 as well? Is this something that could be user activated if a public IPV6 updates (mine isn't static when using my ISPs default config)

Can confim - absolutely great investment as a travel router. I have the same one.

No, it doesn't work with IPv6 yet. We still need to implement in our infrastructure.

It would make my life a lot easier when you guys implement that. Then I can stop trying to setup VPS' lol