| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- // Copyright (c) Tailscale Inc & AUTHORS
- // SPDX-License-Identifier: BSD-3-Clause
- package main
- import (
- "encoding/binary"
- "github.com/google/nftables"
- "github.com/google/nftables/expr"
- "tailscale.com/types/ptr"
- )
- func init() {
- addFirewall = addFirewallLinux
- }
- func addFirewallLinux() error {
- c, err := nftables.New()
- if err != nil {
- return err
- }
- // Create a new table
- table := &nftables.Table{
- Family: nftables.TableFamilyIPv4, // TableFamilyINet doesn't work (why?. oh well.)
- Name: "filter",
- }
- c.AddTable(table)
- // Create a new chain for incoming traffic
- inputChain := &nftables.Chain{
- Name: "input",
- Table: table,
- Type: nftables.ChainTypeFilter,
- Hooknum: nftables.ChainHookInput,
- Priority: nftables.ChainPriorityFilter,
- Policy: ptr.To(nftables.ChainPolicyDrop),
- }
- c.AddChain(inputChain)
- // Allow traffic from the loopback interface
- c.AddRule(&nftables.Rule{
- Table: table,
- Chain: inputChain,
- Exprs: []expr.Any{
- &expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},
- &expr.Cmp{
- Op: expr.CmpOpEq,
- Register: 1,
- Data: []byte("lo"),
- },
- &expr.Verdict{
- Kind: expr.VerdictAccept,
- },
- },
- })
- // Accept established and related connections
- c.AddRule(&nftables.Rule{
- Table: table,
- Chain: inputChain,
- Exprs: []expr.Any{
- &expr.Ct{
- Register: 1,
- Key: expr.CtKeySTATE,
- },
- &expr.Bitwise{
- SourceRegister: 1,
- DestRegister: 1,
- Len: 4,
- Mask: binary.NativeEndian.AppendUint32(nil, 0x06), // CT_STATE_BIT_ESTABLISHED | CT_STATE_BIT_RELATED
- Xor: binary.NativeEndian.AppendUint32(nil, 0),
- },
- &expr.Cmp{
- Op: expr.CmpOpNeq,
- Register: 1,
- Data: binary.NativeEndian.AppendUint32(nil, 0x00),
- },
- &expr.Verdict{
- Kind: expr.VerdictAccept,
- },
- },
- })
- // Allow TCP packets in that don't have the SYN bit set, even if they're not
- // ESTABLISHED or RELATED. This is because the test suite gets TCP
- // connections up & idle (for HTTP) before it conditionally installs these
- // firewall rules. But because conntrack wasn't previously active, existing
- // TCP flows aren't ESTABLISHED and get dropped. So this rule allows
- // previously established TCP connections that predates the firewall rules
- // to continue working, as they don't have conntrack state.
- c.AddRule(&nftables.Rule{
- Table: table,
- Chain: inputChain,
- Exprs: []expr.Any{
- &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},
- &expr.Cmp{
- Op: expr.CmpOpEq,
- Register: 1,
- Data: []byte{0x06}, // TCP
- },
- &expr.Payload{ // get TCP flags
- DestRegister: 1,
- Base: 2,
- Offset: 13, // flags
- Len: 1,
- },
- &expr.Bitwise{
- SourceRegister: 1,
- DestRegister: 1,
- Len: 1,
- Mask: []byte{2}, // TCP_SYN
- Xor: []byte{0},
- },
- &expr.Cmp{
- Op: expr.CmpOpNeq,
- Register: 1,
- Data: []byte{2}, // TCP_SYN
- },
- &expr.Verdict{
- Kind: expr.VerdictAccept,
- },
- },
- })
- return c.Flush()
- }
|