Skip to content

Instantly share code, notes, and snippets.

@gmeeker
Last active March 21, 2024 02:00
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gmeeker/5e9af73fcf213c67cd86794f506520e6 to your computer and use it in GitHub Desktop.
Save gmeeker/5e9af73fcf213c67cd86794f506520e6 to your computer and use it in GitHub Desktop.
OpenWRT squid proxy with authentication

OpenWRT installation of HTTP proxy with authentication

Based on OpenWRT: 18.06.1

(Note: using tinyproxy might accomplish this with less work, but only 1.10 supports authentication. As of December 2018, OpenWRT does not include that version. However, squid also supports other authentication methods so this guide may remain useful.)

I wanted to turn an ordinary WiFi router into an HTTP proxy, but it turns out that the guides I found are for transparent proxies, and worse, OpenWRT doesn't compile authentication into squid!

Official OpenWRT guide to Squid (don't follow these steps blindly, as its only purpose is HTTP caching):

https://openwrt.org/docs/guide-user/services/proxy/proxy.squid

First install and setup OpenWRT. I changed the IP address to 192.168.10.1 to differentiate from standard routers (more on that later...) Then you'll need to build a customized squid package. You could also build squid into the firmware image but that's not the default and I didn't try that.

Setup Linux for compiling OpenWRT

My approach was to use docker:

docker run -it ubuntu

You must then run adduser because OpenWRT will refuse to compile as root. You could also use an existing machine, or create a VM but I found docker helpful to start from scratch.

Patching OpenWRT source code

In the step below, after downloading the source and before compiling, replace feeds/packages/net/squid/Makefile with the following. This will compile basic authentication and include the additional files in the package. This can be modified to compile the other authentication methods.

#
# Copyright (C) 2006-2015 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#

include $(TOPDIR)/rules.mk

PKG_NAME:=squid
PKG_VERSION:=3.5.27
PKG_RELEASE:=1

PKG_LICENSE:=GPL-2.0
PKG_MAINTAINER:=Marko Ratkaj <marko.ratkaj@sartura.hr>

PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=http://www3.us.squid-cache.org/Versions/v3/3.5/ \
	http://www2.pl.squid-cache.org/Versions/v3/3.5/ \
	http://www.squid-cache.org/Versions/v3/3.5/
PKG_HASH:=5ddb4367f2dc635921f9ca7a59d8b87edb0412fa203d1543393ac3c7f9fef0ec

PKG_BUILD_PARALLEL:=1
PKG_INSTALL:=1

include $(INCLUDE_DIR)/package.mk

define Package/squid/Default
  SECTION:=net
  CATEGORY:=Network
  SUBMENU:=Web Servers/Proxies
  URL:=http://www.squid-cache.org/
  MENU:=1
endef

define Package/squid
  $(call Package/squid/Default)
  DEPENDS:=+libopenssl +libpthread +librt +libltdl +libstdcpp
  TITLE:=full-featured Web proxy cache
endef

define Package/squid/description
  Squid is a caching proxy for the Web supporting HTTP, HTTPS, FTP, and more.
  It reduces bandwidth and improves response times by caching and reusing
  frequently-requested web pages.
endef

define Package/squid-mod-cachemgr
  $(call Package/squid/Default)
  DEPENDS:=squid
  TITLE:=Web based proxy manager and reporting tool
endef

CONFIGURE_ARGS += \
	--config-cache \
	--datadir=/usr/share/squid \
	--libexecdir=/usr/lib/squid \
	--sysconfdir=/etc/squid \
	--enable-shared \
	--disable-static \
	--enable-icmp \
	--enable-delay-pools \
	--enable-icap-client \
	--enable-kill-parent-hack \
	--disable-snmp \
	--enable-ssl \
	--enable-ssl-crtd \
	--enable-cache-digests \
	--enable-linux-netfilter \
	--disable-unlinkd \
	--enable-x-accelerator-vary \
	--disable-translation \
	--disable-auto-locale \
	--with-dl \
	--with-pthreads \
	--without-expat \
	--without-libxml2 \
	--without-gnutls \
	--without-nettle \
	--with-openssl=$(STAGING_DIR)/usr \
	--enable-epoll \
	--with-maxfd=4096 \
	--enable-external-acl-helpers \
	--disable-auth-negotiate \
	--disable-auth-ntlm \
	--disable-auth-digest \
	--enable-auth-basic \
	--disable-arch-native \
	--with-krb5-config=no \
	--without-mit-krb5 \
	--without-libcap \
	--without-netfilter-conntrack

CONFIGURE_VARS += \
	ac_cv_header_linux_netfilter_ipv4_h=yes \
	ac_cv_epoll_works=yes \
	squid_cv_gnu_atomics=no

define Build/Compile
	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/lib all
	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
		DESTDIR="$(PKG_INSTALL_DIR)" \
		install
endef

define Package/squid/install
	$(INSTALL_DIR) $(1)/usr/sbin
	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/squid $(1)/usr/sbin/

	$(INSTALL_DIR) $(1)/usr/lib/squid
	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/squid/ssl_crtd $(1)/usr/lib/squid
	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/squid/basic_db_auth $(1)/usr/lib/squid
	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/squid/basic_fake_auth $(1)/usr/lib/squid
	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/squid/basic_getpwnam_auth $(1)/usr/lib/squid
	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/squid/basic_msnt_multi_domain_auth $(1)/usr/lib/squid
	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/squid/basic_ncsa_auth $(1)/usr/lib/squid
	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/squid/basic_pop3_auth $(1)/usr/lib/squid
	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/squid/basic_radius_auth $(1)/usr/lib/squid
	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/squid/basic_smb_auth $(1)/usr/lib/squid
	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/squid/basic_smb_auth.sh $(1)/usr/lib/squid
	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/squid/basic_smb_lm_auth $(1)/usr/lib/squid

	$(INSTALL_DIR) $(1)/etc/config
	$(INSTALL_CONF) ./files/squid.config $(1)/etc/config/squid

	$(INSTALL_DIR) $(1)/etc/squid
	$(INSTALL_CONF) $(PKG_INSTALL_DIR)/etc/squid/mime.conf $(1)/etc/squid/
	$(INSTALL_CONF) ./files/squid.conf $(1)/etc/squid/

	$(INSTALL_DIR) $(1)/etc/init.d/
	$(INSTALL_BIN) ./files/squid.init $(1)/etc/init.d/squid

	$(INSTALL_DIR) $(1)/usr/share/squid/icons/
	$(CP) $(PKG_INSTALL_DIR)/usr/share/squid/icons/* $(1)/usr/share/squid/icons/

	$(INSTALL_DIR) $(1)/usr/share/squid/errors/templates/
	$(CP) $(PKG_INSTALL_DIR)/usr/share/squid/errors/templates/* $(1)/usr/share/squid/errors/templates/
endef

define Package/squid-mod-cachemgr/install
	$(INSTALL_DIR) $(1)/www/cgi-bin/
	$(CP) $(PKG_INSTALL_DIR)/usr/lib/squid/cachemgr.cgi $(1)/www/cgi-bin/
endef

$(eval $(call BuildPackage,squid))
$(eval $(call BuildPackage,squid-mod-cachemgr))

Compiling OpenWRT

Figure out the architecture of your router and refer here:

https://openwrt.org/docs/guide-developer/quickstart-build-images

I wasn't able to just build just squid, so I built the entire thing. This can take hours, so if using docker, don't exit until everything is verified (because you'll lose the build directory). Look for the squid package. For Linksys WRT32X, it will be called squid_3.5.27-1_arm_cortex-a9_vfpv3.ipk (you can use the stock firmware instead of the one you just built.) Use docker cp to copy the file locally.

Installing squid

Run scp filename root@192.168.10.1/root/ to put it on the router. Then: opkg install /root/squid_3.5.27-1_arm_cortex-a9_vfpv3.ipk (Is this right? I don't remember...)

Firewall rules

Because we're not installing a transparent proxy, we don't want to forward traffic. Disable the *config forwarding# section in /etc/config/firewall. You also don't need config redirect which is for transparent proxies. Run:

/etc/init.d/firewall reload
/etc/init.d/firewall restart

Config file should look something like this:

config defaults
	option syn_flood	1
	option input		ACCEPT
	option output		ACCEPT
	option forward		REJECT
# Uncomment this line to disable ipv6 rules
#	option disable_ipv6	1

config zone
	option name		lan
	list   network		'lan'
	option input		ACCEPT
	option output		ACCEPT
	option forward		ACCEPT

config zone
	option name		wan
	list   network		'wan'
	list   network		'wan6'
	option input		REJECT
	option output		ACCEPT
	option forward		REJECT
	option masq		1
	option mtu_fix		1

#config forwarding
#	option src		lan
#	option dest		wan

# We need to accept udp packets on port 68,
# see https://dev.openwrt.org/ticket/4108
config rule
	option name		Allow-DHCP-Renew
	option src		wan
	option proto		udp
	option dest_port	68
	option target		ACCEPT
	option family		ipv4

# Allow IPv4 ping
config rule
	option name		Allow-Ping
	option src		wan
	option proto		icmp
	option icmp_type	echo-request
	option family		ipv4
	option target		ACCEPT

config rule
	option name		Allow-IGMP
	option src		wan
	option proto		igmp
	option family		ipv4
	option target		ACCEPT

# Allow DHCPv6 replies
# see https://dev.openwrt.org/ticket/10381
config rule
	option name		Allow-DHCPv6
	option src		wan
	option proto		udp
	option src_ip		fc00::/6
	option dest_ip		fc00::/6
	option dest_port	546
	option family		ipv6
	option target		ACCEPT

config rule
	option name		Allow-MLD
	option src		wan
	option proto		icmp
	option src_ip		fe80::/10
	list icmp_type		'130/0'
	list icmp_type		'131/0'
	list icmp_type		'132/0'
	list icmp_type		'143/0'
	option family		ipv6
	option target		ACCEPT

# Allow essential incoming IPv6 ICMP traffic
config rule
	option name		Allow-ICMPv6-Input
	option src		wan
	option proto	icmp
	list icmp_type		echo-request
	list icmp_type		echo-reply
	list icmp_type		destination-unreachable
	list icmp_type		packet-too-big
	list icmp_type		time-exceeded
	list icmp_type		bad-header
	list icmp_type		unknown-header-type
	list icmp_type		router-solicitation
	list icmp_type		neighbour-solicitation
	list icmp_type		router-advertisement
	list icmp_type		neighbour-advertisement
	option limit		1000/sec
	option family		ipv6
	option target		ACCEPT

# Allow essential forwarded IPv6 ICMP traffic
config rule
	option name		Allow-ICMPv6-Forward
	option src		wan
	option dest		*
	option proto		icmp
	list icmp_type		echo-request
	list icmp_type		echo-reply
	list icmp_type		destination-unreachable
	list icmp_type		packet-too-big
	list icmp_type		time-exceeded
	list icmp_type		bad-header
	list icmp_type		unknown-header-type
	option limit		1000/sec
	option family		ipv6
	option target		ACCEPT

config rule
	option name		Allow-IPSec-ESP
	option src		wan
	option dest		lan
	option proto		esp
	option target		ACCEPT

config rule
	option name		Allow-ISAKMP
	option src		wan
	option dest		lan
	option dest_port	500
	option proto		udp
	option target		ACCEPT

# include a file with users custom iptables rules
config include
	option path /etc/firewall.user


### EXAMPLE CONFIG SECTIONS
# do not allow a specific ip to access wan
#config rule
#	option src		lan
#	option src_ip	192.168.45.2
#	option dest		wan
#	option proto	tcp
#	option target	REJECT

# block a specific mac on wan
#config rule
#	option dest		wan
#	option src_mac	00:11:22:33:44:66
#	option target	REJECT

# block incoming ICMP traffic on a zone
#config rule
#	option src		lan
#	option proto	ICMP
#	option target	DROP

# port redirect port coming in on wan to lan
#config redirect
#	option src			wan
#	option src_dport	80
#	option dest			lan
#	option dest_ip		192.168.16.235
#	option dest_port	80
#	option proto		tcp

# port redirect of remapped ssh port (22001) on wan
#config redirect
#	option src		wan
#	option src_dport	22001
#	option dest		lan
#	option dest_port	22
#	option proto		tcp

### FULL CONFIG SECTIONS
#config rule
#	option src		lan
#	option src_ip	192.168.45.2
#	option src_mac	00:11:22:33:44:55
#	option src_port	80
#	option dest		wan
#	option dest_ip	194.25.2.129
#	option dest_port	120
#	option proto	tcp
#	option target	REJECT

#config redirect
#	option src		lan
#	option src_ip	192.168.45.2
#	option src_mac	00:11:22:33:44:55
#	option src_port		1024
#	option src_dport	80
#	option dest_ip	194.25.2.129
#	option dest_port	120
#	option proto	tcp

Configuring squid

Next edit /etc/squid/squid.conf to require authentication. I think I got this from posts about Squid on Linux, not OpenWRT. Note that this assumes you've changed the IP address to 192.168.10.1.

auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords
auth_param basic realm Anarchy
acl authenticated proxy_auth REQUIRED
http_access allow authenticated

acl localnet src 10.0.0.0/8
acl localnet src 172.16.0.0/12
acl localnet src 192.168.0.0/16
acl localnet src fc00::/7
acl localnet src fe80::/10
acl router dst 192.168.10.1

acl ssl_ports port 443

acl safe_ports port 80
acl safe_ports port 21
acl safe_ports port 443
acl safe_ports port 70
acl safe_ports port 210
acl safe_ports port 1025-65535
acl safe_ports port 280
acl safe_ports port 488
acl safe_ports port 591
acl safe_ports port 777
acl connect method connect

http_access deny !safe_ports
http_access deny connect !ssl_ports

http_access allow localhost manager
http_access deny manager

http_access deny to_localhost

http_access deny !localnet
http_access allow localhost
http_access allow router

http_access allow authenticated

http_access deny all

refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320

access_log stdout
cache_log /dev/null
cache_store_log stdio:/dev/null
logfile_rotate 0

logfile_daemon /dev/null

Passwords

Finally create at least one password in /etc/squid/passwords. For testing username:password produces this:

username:ifeLyo3ULzzgA

I didn't look into this much, but OpenWRT's encryption libraries don't support the usual Apache MD5 passwords from htpasswd. I had to use insecure CRYPT encryption to get this to work. Since OpenWRT doesn't have htpasswd this has to be run on the Linux machine. If you really care, you'd probably use something other than basic auth. That said, here's my approach.

apt-get install apache2-utils
htpasswd -nbd username password

Paste that output into /etc/squid/passwords

Restart squid

/etc/init.d/squid restart

Access proxy server

This setup varies by operating system, but you can set configure the proxy address at 192.168.10.1:3128 or you can use PAC. Because I didn't use 192.168.1.1 I can write a .pac file like this:

function FindProxyForURL(url, host) {
  if (shExpMatch(host, "localhost")) {
    return "DIRECT";
  }
  if (isInNet(myIpAddress(), "192.168.10.0", "255.255.255.0")) {
    return "PROXY 192.168.10.1:3128; DIRECT";
  } else {
    return "DIRECT";
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment