Skip to content

Instantly share code, notes, and snippets.

@philotas
Forked from triwav/roku-proxy-setup.md
Created June 15, 2022 09:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save philotas/6be62e5fc50dcf5a5965eb4396c7ccc0 to your computer and use it in GitHub Desktop.
Save philotas/6be62e5fc50dcf5a5965eb4396c7ccc0 to your computer and use it in GitHub Desktop.
Roku Proxy Setup

This is largely based off of this article by Hulu and their roku-dev-cli tool.

Requirements:
The main requirement is a Mac with 2 available network interfaces WIFI <-> WIFI, LAN <-> WIFI, etc. This should work on other platforms as well but isn't covered here.

Setup
The first thing we need is Homebrew. If you've never used it before it's a great package manager for macOS that makes installing programs easier. Open Terminal and paste
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
and hit enter

Next we need to install mitmproxy. We do this by running
brew install mitmproxy
and hit enter

The next step is we need to actually route our traffic through our proxy. Platforms like iOS or Android allow you to set a proxy. Roku does not have this capability so we need to inject ourselves in the middle between the Roku device and the server it's trying to hit. We do this using macOs' Internet Connection Sharing (ICS). By default, ICS won't route through our proxy though so even though the data is going through the proxy computer it still won't show up. We are going to use the built in pfctl packet filter to remedy this.

Run the following commands:
cp /etc/pf.conf ~
Makes a backup of your pf config file in your home directory

sudo nano /etc/pf.conf
Opens our config in a text editor so we can modify it

Look for for the lines:
scrub-anchor "com.apple/*"
nat-anchor "com.apple/*"
rdr-anchor "com.apple/*"
and paste the following below them:
# Port forwarding for mitmproxy
rdr pass on bridge100 inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
rdr pass on bridge100 inet proto tcp from any to any port 443 -> 127.0.0.1 port 8080
make sure you paste them above the following lines:
dummynet-anchor "com.apple/*"
anchor "com.apple/*"

Hit ctrl-o to save and then ctrl-q to quit

This redirects http requests (80) and https requests (443) from our ICS connection (bridge100) to our local machine on port 8080 which is the default for mitmproxy. Http requests will work without any issues but https will not without help.

Run the following to confirm there aren't any issues with the file:
sudo pfctl -v -n -f /etc/pf.conf

If everything looks good run:
sudo pfctl -ef /etc/pf.conf
to setup our rules.

Now that we have our rules in place setup ICS by going to
System Preferences -> Sharing -> Internet Sharing.

Select which device you want to share the internet from and which you want to share to. If you're doing wifi then be sure to set your wifi options as well.

Click the checkbox next to Internet Sharing to turn on sharing

Certificate Generation
*Note the following is only if you don't have a certificate already

It's time to fire up mitmproxy to get it to create our certificate. We do that with the following:
sudo mitmweb
After it starts up you can hit ctrl-c to shut it down.

Doing this should cause mitmproxy to generate a pem we can use to intercept https request. We need to copy the certificate to our project's source directory with something like this
cp ~/.mitmproxy/mitmproxy-ca-cert.pem <YOUR-PROJECT-PATH>/source/mitmproxy.crt

Project modification:
If you look at Hulu's source code you can see they're replacing all references to setCertificatesFile(.*) with setCertificatesFile("pkg:/source/mitmproxy.crt"). Since you're required to call setCertificatesFile() on your roUrlTransfer requests, you can do a find and replace in your code base doing the same. Most likely you're using the standard "common:/certs/ca-bundle.crt" path so you could just search for that and replace with "pkg:/source/mitmproxy.crt".

That will correctly handle any of your https roUrlTransfer requests. But other things like RAF, Poster and Video still won't work though. For these you need to do the following:

RAF:
add a call to setCertificatesFile("pkg:/source/mitmproxy.crt") on your raf object

Poster:
Setting m.top.getHttpAgent().setCertificatesFile("pkg:/source/mitmproxy.crt") in your scene's init will handle all your https images and even most of your video requests. There are a few cases where this doesn't work though.

Video:
Video works a little different in that it actually uses a field on the ContentNode itself. Setting content.HttpCertificatesFile = "pkg:/source/mitmproxy.crt" on the ContentNode you pass to your Video node should correctly handle https requests there.

*Setting these values to "common:/certs/ca-bundle.crt" seems to not cause problems and results in the ability to do a find and replace for "common:/certs/ca-bundle.crt" to quickly enable proxying.

Run It
Start up your proxy:
sudo mitmweb --ignore-hosts .\*roku.\*\.com --set client_certs=<YOUR-PROJECT-PATH>/source/mitmproxy.crt

Build your app and run it on your Roku device. Be sure that your Roku device is actually connected to Mac's connection. You can verify this by looking at the IP address. It could be in the 192.168.2.X subdomain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment