lost and found ( for me ? )

Squid : Configure Squid transparent proxy(tproxy) on CentOS7

Here are logs when setting up Squid with tproxy on CentOS7.

[ CentOS7 ]

Client --------------------- eth0 CentOS7 eth1 --------------------- apache
<- 192.168.180.0/24 >                       <- 192.168.122.0/24 >

CentOS7 eth1 : 192.168.180.209 
CentOS7 eth0 : 192.168.122.209

Apache : 192.168.122.227

Client : 192.168.180.100
Default GW of client : 192.168.180.209

Install squid
# cat /etc/centos-release
CentOS Linux release 7.2.1511 (Core)


# yum install squid

# squid -v
Squid Cache: Version 3.3.8

Squid.conf
# grep -v ^# /etc/squid/squid.conf | grep -v ^$
acl localnet src 10.0.0.0/8 # RFC1918 possible internal network
acl localnet src 172.16.0.0/12 # RFC1918 possible internal network
acl localnet src 192.168.0.0/16 # RFC1918 possible internal network
acl localnet src fc00::/7       # RFC 4193 local private network range
acl localnet src fe80::/10      # RFC 4291 link-local (directly plugged) machines
acl lan src 192.168.180.0/24
acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localhost manager
http_access allow lan
http_access deny manager
http_access allow localnet
http_access allow localhost
http_access deny all
http_port 3128 tproxy
coredump_dir /var/spool/squid
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

Start squid
# systemctl enable squid

# systemctl start squid

[ Configure Firewalld ]

- Zone

Eth0 and eth1 belongs to a zone “internal”
# firewall-cmd --get-active-zones
internal
 interfaces: eth0 eth1

Default zone of eth0 and eth1 was public, but I changed a zone to internal by adding “ZONE=internal” in ifcfg-eth[x] files.
# less /etc/firewalld/firewalld.conf

# firewalld config file

# default zone
# The default zone used if an empty zone string is used.
# Default: public
DefaultZone=public

# grep ^ZONE /etc/sysconfig/network-scripts/ifcfg-eth0
ZONE=internal

# grep ^ZONE /etc/sysconfig/network-scripts/ifcfg-eth1
ZONE=internal

Allow ssh, http, 3128 on this zone.
# firewall-cmd --zone=internal --add-service=ssh --permanent
success

# firewall-cmd --zone=internal --add-service=http --permanent
success

# firewall-cmd --zone=internal --add-port=3128/tcp --permanent
success

Confirm that “masquerade” is disabled on the zone.
When masquerade is enabled, tproxy did not work...
# firewall-cmd --zone=internal --list-all
internal (active)
 interfaces: eth0 eth1
 sources:
 services: dhcpv6-client http ipp-client mdns samba-client ssh
 ports: 3128/tcp
 masquerade: no
 forward-ports:
 icmp-blocks:
 rich rules:

The configuration files are under /etc/firewalld/zones directory.
# cat /etc/firewalld/zones/internal.xml
<?xml version="1.0" encoding="utf-8"?>
<zone>
 <short>Internal</short>
 <description>For use on internal networks. You mostly trust the other computers on the networks to not harm your computer. Only selected incoming connections are accepted.</description>
 <service name="mdns"/>
 <service name="http"/>
 <service name="ipp-client"/>
 <service name="dhcpv6-client"/>
 <service name="ssh"/>
 <service name="samba-client"/>
 <port protocol="tcp" port="3128"/>
</zone>

- Add direct rules

Create a chain “DIVERT” in mangle table.
# firewall-cmd --permanent --direct --add-chain ipv4 mangle DIVERT
success

Add rules

# firewall-cmd --permanent --direct --add-chain ipv4 mangle DIVERT
success

# firewall-cmd --permanent --direct --add-rule ipv4 mangle PREROUTING 0 -p tcp -m socket -j DIVERT
success

# firewall-cmd --permanent --direct --add-rule ipv4 mangle DIVERT 0 -j MARK --set-mark 1
success

# firewall-cmd --permanent --direct --add-rule ipv4 mangle DIVERT 0 -j ACCEPT
success

# firewall-cmd --permanent --direct --add-rule ipv4 mangle PREROUTING 0 -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 3128
success

Those rules are saved in /etc/firewalld/direct.xml
# cat /etc/firewalld/direct.xml
<?xml version="1.0" encoding="utf-8"?>
<direct>
 <chain table="mangle" ipv="ipv4" chain="DIVERT"/>
 <rule priority="0" table="mangle" ipv="ipv4" chain="PREROUTING">-p tcp -m socket -j DIVERT</rule>
 <rule priority="0" table="mangle" ipv="ipv4" chain="PREROUTING">-p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 3128</rule>
 <rule priority="0" table="mangle" ipv="ipv4" chain="DIVERT">-j MARK --set-mark 1</rule>
 <rule priority="0" table="mangle" ipv="ipv4" chain="DIVERT">-j ACCEPT</rule>
</direct>

Enable ip_forward
# echo 1 > /proc/sys/net/ipv4/ip_forward

# cat /proc/sys/net/ipv4/ip_forward
1


# tail -3 /etc/sysctl.d/99-sysctl.conf
# For more information, see sysctl.conf(5) and sysctl.d(5).
net.ipv4.ip_forward = 1

Add policy base routing.
# ip rule add fwmark 1 lookup 100

# ip route add local 0.0.0.0/0 dev lo table 100

# ip rule show
0: from all lookup local
32765: from all fwmark 0x1 lookup 100
32766: from all lookup main
32767: from all lookup default


# grep -v ^# /etc/rc.local

ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100

touch /var/lock/subsys/local


# ls -l /etc/rc.local
lrwxrwxrwx. 1 root root 13  4月 16 01:11 /etc/rc.local -> rc.d/rc.local


# chmod +x /etc/rc.d/rc.local

Access to the apache from the client.
# curl http://192.168.122.227

Access log on the squid
# tail -f /var/log/squid/access.log
1460736537.966      2 192.168.180.100 TCP_MISS/404 606 GET http://192.168.122.227/a35 - HIER_DIRECT/192.168.122.227 text/html
1460738390.571      5 192.168.180.100 TCP_MISS/404 605 GET http://192.168.122.227/a0 - HIER_DIRECT/192.168.122.227 text/html
1460738391.591      3 192.168.180.100 TCP_MISS/404 605 GET http://192.168.122.227/a1 - HIER_DIRECT/192.168.122.227 text/html

Access log on the apache.
I can see client IP on the apache.
# tail -f /var/log/httpd/access_log
192.168.180.100 - - [16/Apr/2016:01:40:45 +0900] "GET /a54 HTTP/1.1" 404 282 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.19.1 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
192.168.180.100 - - [16/Apr/2016:01:40:46 +0900] "GET /a55 HTTP/1.1" 404 282 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.19.1 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"
192.168.180.100 - - [16/Apr/2016:01:40:47 +0900] "GET /a56 HTTP/1.1" 404 282 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.19.1 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"

Capture data on the apache.
192.168.180.100 is the client IP.
# tshark -n -i eth0 port 80 | grep -i get
Running as user "root" and group "root". This could be dangerous.
Capturing on eth0
0.000921769 192.168.180.100 -> 192.168.122.227 HTTP 383 GET /a121 HTTP/1.1
1.019652308 192.168.180.100 -> 192.168.122.227 HTTP 383 GET /a122 HTTP/1.1
2.038371117 192.168.180.100 -> 192.168.122.227 HTTP 383 GET /a123 HTTP/1.1

Capture data on the squid ( eth0 )

# tshark -n -i eth0 port 80 | grep GET
Running as user "root" and group "root". This could be dangerous.
Capturing on 'eth0'
32   4 0.000587842 192.168.180.100 -> 192.168.122.227 HTTP 383 GET /a205 HTTP/1.1
14 1.018408367 192.168.180.100 -> 192.168.122.227 HTTP 383 GET /a206 HTTP/1.1
25 2.034699001 192.168.180.100 -> 192.168.122.227 HTTP 383 GET /a207 HTTP/1.1

Capture data on the squid ( eth1 )
# tshark -n -i eth1 port 80 | grep GET
Running as user "root" and group "root". This could be dangerous.
Capturing on 'eth1'
36   4 0.000789816 192.168.180.100 -> 192.168.122.227 HTTP 248 GET /a182 HTTP/1.1
16 1.018005133 192.168.180.100 -> 192.168.122.227 HTTP 248 GET /a183 HTTP/1.1
28 2.034541993 192.168.180.100 -> 192.168.122.227 HTTP 248 GET /a184 HTTP/1.1

[ Squid tproxy on CentOS6 ]

# rpm -qa | grep squid
squid-3.1.23-9.el6.x86_64

# iptables -F
# iptables -F -t nat
# iptables -F -t mangle

# ip rule add fwmark 1 lookup 100
# ip route add local 0.0.0.0/0 dev lo table 100

# iptables -t mangle -N DIVERT
# iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
# iptables -t mangle -A DIVERT -j MARK --set-mark 1
# iptables -t mangle -A DIVERT -j ACCEPT
# iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 3128

# echo 1 > /proc/sys/net/ipv4/ip_forward

# iptables -L -n -t mangle
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DIVERT     tcp  --  0.0.0.0/0            0.0.0.0/0           socket
TPROXY     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:80 TPROXY redirect 0.0.0.0:3128 mark 0x1/0x1

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

Chain DIVERT (1 references)
target     prot opt source               destination
MARK       all  --  0.0.0.0/0            0.0.0.0/0           MARK set 0x1
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0

# iptables -L -n -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
[root@centos6-squid ~]# iptables -L -n
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination


# grep -v ^# /etc/squid/squid.conf | grep -v ^$
acl manager proto cache_object
acl localhost src 127.0.0.1/32 ::1
acl to_localhost dst 127.0.0.0/8 0.0.0.0/32 ::1
acl localnet src 10.0.0.0/8     # RFC1918 possible internal network
acl localnet src 172.16.0.0/12  # RFC1918 possible internal network
acl localnet src 192.168.0.0/16 # RFC1918 possible internal network
acl localnet src fc00::/7       # RFC 4193 local private network range
acl localnet src fe80::/10      # RFC 4291 link-local (directly plugged) machines
acl lan src 192.168.100.0/24
acl SSL_ports port 443
acl Safe_ports port 80          # http
acl Safe_ports port 21          # ftp
acl Safe_ports port 443         # https
acl Safe_ports port 70          # gopher
acl Safe_ports port 210         # wais
acl Safe_ports port 1025-65535  # unregistered ports
acl Safe_ports port 280         # http-mgmt
acl Safe_ports port 488         # gss-http
acl Safe_ports port 591         # filemaker
acl Safe_ports port 777         # multiling http
acl CONNECT method CONNECT
http_access allow lan
http_access allow manager localhost
http_access deny manager
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localnet
http_access allow localhost
http_access deny all
http_port 3128 tproxy
coredump_dir /var/spool/squid
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