apernet / OpenGFW

OpenGFW is a flexible, easy-to-use, open source implementation of GFW (Great Firewall of China) on Linux
https://gfw.dev/
Mozilla Public License 2.0
9.32k stars 703 forks source link

Hidden dependency to iptables command #101

Closed macie closed 4 months ago

macie commented 4 months ago

What happened?

When command is run with configs from README.md and there is no iptables command, it throws an error failed to parse config.

How should it be?

Better error message / instructions how to install on systems other than OpenWrt.

How to reproduce?

$ go run -c config.yaml rules.yaml
2024-03-12T13:41:13+01:00       FATAL   failed to parse config  {"error": "invalid config: io: exec: \"iptables\": executable file not found in $PATH"}

Content of config.yaml:

io:
  queueSize: 1024
  rcvBuf: 4194304
  sndBuf: 4194304
  local: true # set to false if you want to run OpenGFW on FORWARD chain

workers:
  count: 4
  queueSize: 16
  tcpMaxBufferedPagesTotal: 4096
  tcpMaxBufferedPagesPerConn: 64
  udpMaxStreams: 4096

Content of rules.yaml:

# A rule must have at least one of "action" or "log" field set.
- name: log horny people
  log: true
  expr: let sni = string(tls?.req?.sni); sni contains "porn" || sni contains "hentai"

- name: block v2ex http
  action: block
  expr: string(http?.req?.headers?.host) endsWith "v2ex.com"

- name: block v2ex https
  action: block
  expr: string(tls?.req?.sni) endsWith "v2ex.com"

- name: block v2ex quic
  action: block
  expr: string(quic?.req?.sni) endsWith "v2ex.com"

- name: block and log shadowsocks
  action: block
  log: true
  expr: fet != nil && fet.yes

- name: block trojan
  action: block
  expr: trojan != nil && trojan.yes

- name: v2ex dns poisoning
  action: modify
  modifier:
    name: dns
    args:
      a: "0.0.0.0"
      aaaa: "::"
  expr: dns != nil && dns.qr && any(dns.questions, {.name endsWith "v2ex.com"})

- name: block google socks
  action: block
  expr: string(socks?.req?.addr) endsWith "google.com" && socks?.req?.port == 80

- name: block wireguard by handshake response
  action: drop
  expr: wireguard?.handshake_response?.receiver_index_matched == true

- name: block bilibili geosite
  action: block
  expr: geosite(string(tls?.req?.sni), "bilibili")

- name: block CN geoip
  action: block
  expr: geoip(string(ip.dst), "cn")

- name: block cidr
  action: block
  expr: cidr(string(ip.dst), "192.168.0.0/16")

Additional info Version 0.2.3.

haruue commented 4 months ago

Which version of OpenWrt did you download that has neither nftables nor iptables? Please provide the download link. I am curious how this variant of OpenWrt implements its firewall.

The current io in OpenGFW is implemented by NFQUEUE, which requires adding an nftables/iptables rule. For machines with nftables installed (determined by whether the nft executable exists), OpenGFW will prioritize using nftables to add this rule. For machines that don't have nftables, but do have iptables, it will use iptables instead. If neither is present, you'll get the error you saw.