1 Commits
Author SHA1 Message Date
kor-elf 1eaf009e56 Merge pull request 'Версия 0.1.1' (#2) from develop into main
Reviewed-on: #2
2026-01-01 21:31:59 +05:00
28 changed files with 179 additions and 824 deletions
+4 -73
View File
@@ -10,7 +10,6 @@ Go-низкоуровневая обёртка для управления [nfta
- Абстракции для работы с IP/IP6/inet/arp/bridge/netdev families - Абстракции для работы с IP/IP6/inet/arp/bridge/netdev families
- Интерфейс для выполнения CLI-команд nftables напрямую - Интерфейс для выполнения CLI-команд nftables напрямую
- Простой и минималистичный API для быстрой интеграции - Простой и минималистичный API для быстрой интеграции
- Добавлена возможность формировать batch-команды и отправлять их в nftables одним вызовом.
## Установка ## Установка
```sh ```sh
@@ -30,13 +29,13 @@ import (
) )
func main() { func main() {
nftClient, err := nft.New() nft, err := nft.New()
if err != nil { if err != nil {
log.Fatalf("nft not found: %v", err) log.Fatalf("nft not found: %v", err)
} }
// Добавить таблицу // Добавить таблицу
if err := nftClient.Table().Add(family.IP, "test"); err != nil { if err := nft.Table().Add(family.IP, "test"); err != nil {
log.Fatalf("table add failed: %v", err) log.Fatalf("table add failed: %v", err)
} }
@@ -44,78 +43,16 @@ func main() {
chainType.Hook = chain.HookOutput chainType.Hook = chain.HookOutput
chainType.Priority = 0 chainType.Priority = 0
chainType.Policy = chain.PolicyAccept chainType.Policy = chain.PolicyAccept
if err := nftClient.Chain().Add(family.IP, "test", "test", chainType); err != nil { if err := nft.Chain().Add(family.IP, "test", "test", chainType); err != nil {
log.Fatalf("table add failed: %v", err) log.Fatalf("table add failed: %v", err)
} }
// Добавить правило (пример: дропать пакеты от 1.2.3.4) // Добавить правило (пример: дропать пакеты от 1.2.3.4)
if err := nftClient.Rule().Add(family.IP, "test", "test", "ip", "saddr", "1.2.3.4", "drop"); err != nil { if err := nft.Rule().Add(family.IP, "test", "test", "ip", "saddr", "1.2.3.4", "drop"); err != nil {
log.Fatalf("rule add failed: %v", err) log.Fatalf("rule add failed: %v", err)
} }
} }
``` ```
### Batch commands
Библиотека поддерживает отправку команд в `nft` через batch-файлы.
Это позволяет заранее сформировать набор команд, например для таблиц, цепочек и правил,
а затем выполнить их одной операцией.
## Пример использования
```go
package main
import (
"log"
"git.kor-elf.net/kor-elf-shield/go-nftables-client"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/chain"
)
func main() {
nftClient, err := nft.New()
if err != nil {
log.Fatalf("nft not found: %v", err)
}
batchBuilder, err := nft.NewBatchBuilder("/tmp/nft_batch")
if err != nil {
log.Fatalf("batch builder init failed: %v", err)
}
defer func() {
_ = batchBuilder.Close()
}()
// Добавить таблицу
if err := batchBuilder.Table().Add(family.IP, "test"); err != nil {
log.Fatalf("table add failed: %v", err)
}
chainType := chain.NewBaseChainOptions(chain.TypeFilter)
chainType.Hook = chain.HookOutput
chainType.Priority = 0
chainType.Policy = chain.PolicyAccept
if err := batchBuilder.Chain().Add(family.IP, "test", "test", chainType); err != nil {
log.Fatalf("table add failed: %v", err)
}
// Добавить правило (пример: дропать пакеты от 1.2.3.4)
if err := batchBuilder.Rule().Add(family.IP, "test", "test", "ip", "saddr", "1.2.3.4", "drop"); err != nil {
log.Fatalf("rule add failed: %v", err)
}
batch := batchBuilder.Build()
defer func() {
_ = batch.Close()
}()
// Выполняет пакет команд после проверки их корректности
if err := nftClient.ExecuteBatchAfterCheck(batch); err != nil {
log.Fatalf("batch execute failed: %v", err)
}
}
```
## Краткое описание API ## Краткое описание API
@@ -139,12 +76,6 @@ nft.Rule().Delete(family family.Type, table, chain string, handle uint64) error
nft.Clear() error // flush ruleset nft.Clear() error // flush ruleset
nft.Version() (Version, error) // информация о версии nftables nft.Version() (Version, error) // информация о версии nftables
nft.Command() command.NFT // ручное выполнение любых nft-команд nft.Command() command.NFT // ручное выполнение любых nft-команд
// ExecuteBatchAfterCheck Выполняет пакет команд после проверки их корректности
nft.ExecuteBatchAfterCheck(batch Batch) error
// ExecuteBatch Выполняет пакет команд
nft.ExecuteBatch(batch Batch) error
``` ```
## Требования ## Требования
-76
View File
@@ -1,76 +0,0 @@
package nft
import (
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract"
contractBatch "git.kor-elf.net/kor-elf-shield/go-nftables-client/contract/batch"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/batch"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/batch/chain"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/batch/rule"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/batch/table"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/pkg"
nftCommand "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/pkg/nft"
)
type batchBuilder struct {
command contract.CommandRun
file *pkg.File
table contractBatch.Table
chain contractBatch.Chain
rule contractBatch.Rule
isBuildBatch bool
}
func NewBatchBuilder(dir string) (contract.BatchBuilder, error) {
file, err := pkg.CreateRandomTmpFile(dir)
if err != nil {
return nil, err
}
command := batch.NewCommand(file)
return &batchBuilder{
command: command,
file: file,
table: table.New(command),
chain: chain.New(command),
rule: rule.New(command),
isBuildBatch: false,
}, nil
}
func (b *batchBuilder) Command() contract.CommandRun {
return b.command
}
func (b *batchBuilder) Clear() error {
args := nftCommand.Clear()
return b.command.Run(args...)
}
func (b *batchBuilder) Table() contractBatch.Table {
return b.table
}
func (b *batchBuilder) Chain() contractBatch.Chain {
return b.chain
}
func (b *batchBuilder) Rule() contractBatch.Rule {
return b.rule
}
func (b *batchBuilder) Build() contract.Batch {
b.isBuildBatch = true
return batch.NewBatch(b.file)
}
func (b *batchBuilder) Close() error {
if b.isBuildBatch {
return nil
}
return b.file.Remove()
}
-46
View File
@@ -1,46 +0,0 @@
package contract
import (
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract/batch"
)
// BatchBuilder is an API for building a batch of commands.
type BatchBuilder interface {
// Command returns the command to run.
Command() CommandRun
// Clear clears all rules.
//
// This command is equivalent to:
// nft flush ruleset
Clear() error
// Table returns an API for working with tables.
Table() batch.Table
// Chain returns an API for working with chains.
Chain() batch.Chain
// Rule returns an API for working with rules.
Rule() batch.Rule
// Build returns a batch of commands.
Build() Batch
// Close closes the batch.
Close() error
}
type Batch interface {
// Args returns the arguments of the batch.
Args() []string
// Check checks the validity of the batch.
Check(command Command) error
// Close closes the batch.
Close() error
// MoveFile moves the batch file to the specified path.
MoveFile(path string) error
}
-46
View File
@@ -1,46 +0,0 @@
package batch
import (
chain2 "git.kor-elf.net/kor-elf-shield/go-nftables-client/chain"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
)
// Chain for working with chains.
type Chain interface {
// Add adds a new chain.
//
// This command is equivalent to:
// nft add chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name}
// nft add chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type (filter|route|nat) hook (ingress|prerouting|forward|input|output|postrouting|egress) priority (priority_value = int32) ;}'
// nft add chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type filter hook (forward|input|output) priority (priority_value = int32) ; policy (accept|drop) ;}'
// nft add chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type (filter|route|nat) hook (ingress|egress) device {device} priority (priority_value = int32) ;}'
Add(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) error
// Create creates a new chain.
// Similar to the Add, but returns an error if the chain already exists.
//
// This command is equivalent to:
// nft create chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name}
// nft create chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type (filter|route|nat) hook (ingress|prerouting|forward|input|output|postrouting|egress) priority (priority_value = int32) ;}'
// nft create chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type filter hook (forward|input|output) priority (priority_value = int32) ; policy (accept|drop) ;}'
// nft create chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type (filter|route|nat) hook (ingress|egress) device {device} priority (priority_value = int32) ;}'
Create(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) error
// Delete deletes a chain.
//
// This command is equivalent to:
// nft delete chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name}
Delete(family family.Type, tableName string, chainName string) error
// Clear clears all rules in a chain.
//
// This command is equivalent to:
// nft flush chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name}
Clear(family family.Type, tableName string, chainName string) error
// Rename renames a chain.
//
// This command is equivalent to:
// nft rename chain (ip|ip6|inet|arp|bridge) {table_name} {old_chain_name} {new_chain_name}
Rename(family family.Type, tableName string, oldChainName string, newChainName string) error
}
-31
View File
@@ -1,31 +0,0 @@
package batch
import "git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
// Rule is the interface for rule manipulation.
type Rule interface {
// Add adds a new rule.
//
// This command is equivalent to:
// nft add rule (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ expr }'
Add(family family.Type, tableName string, chainName string, expr ...string) error
// Insert inserts a new rule.
// Inserted rules are placed at the beginning of the chain, by default.
//
// This command is equivalent to:
// nft insert rule (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ expr }'
Insert(family family.Type, tableName string, chainName string, expr ...string) error
// Replace replaces a rule.
//
// This command is equivalent to:
// nft replace rule (ip|ip6|inet|arp|bridge) {table_name} {chain_name} {handle} '{ expr }'
Replace(family family.Type, tableName string, chainName string, handle uint64, expr ...string) error
// Delete deletes a rule.
//
// This command is equivalent to:
// nft delete rule (ip|ip6|inet|arp|bridge) {table_name} {chain_name} {handle}
Delete(family family.Type, tableName string, chainName string, handle uint64) error
}
-24
View File
@@ -1,24 +0,0 @@
package batch
import "git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
// Table for working with tables.
type Table interface {
// AddTable adds a new table.
//
// This command is equivalent to:
// nft add table (ip|ip6|inet|arp|bridge) {table_name}
Add(family family.Type, tableName string) error
// DeleteTable deletes a table.
//
// This command is equivalent to:
// nft delete table (ip|ip6|inet|arp|bridge) {table_name}
Delete(family family.Type, tableName string) error
// ClearTable clears all rules in a table.
//
// This command is equivalent to:
// nft flush table (ip|ip6|inet|arp|bridge) {table_name}
Clear(family family.Type, tableName string) error
}
-13
View File
@@ -1,13 +0,0 @@
package contract
type CommandRun interface {
// Run executes nft command.
Run(arg ...string) error
}
type Command interface {
CommandRun
// RunWithOutput Run nft command with output.
RunWithOutput(arg ...string) (string, error)
}
-37
View File
@@ -1,37 +0,0 @@
package contract
import "git.kor-elf.net/kor-elf-shield/go-nftables-client/contract/nft"
// NFT A client for working with nftables
type NFT interface {
// Command returns the command used to execute nft.
// You can execute your raw request.
Command() Command
// ExecuteBatchAfterCheck executes a batch of commands after checking the validity of the batch.
ExecuteBatchAfterCheck(batch Batch) error
// ExecuteBatch executes a batch of commands.
ExecuteBatch(batch Batch) error
// Clear clears all rules.
//
// This command is equivalent to:
// nft flush ruleset
Clear() error
// Version returns the version of nftables.
//
// This command is equivalent to:
// nft -V
Version() (nft.Version, error)
// Table returns an API for working with tables.
Table() nft.Table
// Chain returns an API for working with chains.
Chain() nft.Chain
// Rule returns an API for working with rules.
Rule() nft.Rule
}
-46
View File
@@ -1,46 +0,0 @@
package nft
import (
chain2 "git.kor-elf.net/kor-elf-shield/go-nftables-client/chain"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
)
// Chain for working with chains.
type Chain interface {
// Add adds a new chain.
//
// This command is equivalent to:
// nft add chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name}
// nft add chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type (filter|route|nat) hook (ingress|prerouting|forward|input|output|postrouting|egress) priority (priority_value = int32) ;}'
// nft add chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type filter hook (forward|input|output) priority (priority_value = int32) ; policy (accept|drop) ;}'
// nft add chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type (filter|route|nat) hook (ingress|egress) device {device} priority (priority_value = int32) ;}'
Add(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) error
// Create creates a new chain.
// Similar to the Add, but returns an error if the chain already exists.
//
// This command is equivalent to:
// nft create chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name}
// nft create chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type (filter|route|nat) hook (ingress|prerouting|forward|input|output|postrouting|egress) priority (priority_value = int32) ;}'
// nft create chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type filter hook (forward|input|output) priority (priority_value = int32) ; policy (accept|drop) ;}'
// nft create chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type (filter|route|nat) hook (ingress|egress) device {device} priority (priority_value = int32) ;}'
Create(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) error
// Delete deletes a chain.
//
// This command is equivalent to:
// nft delete chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name}
Delete(family family.Type, tableName string, chainName string) error
// Clear clears all rules in a chain.
//
// This command is equivalent to:
// nft flush chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name}
Clear(family family.Type, tableName string, chainName string) error
// Rename renames a chain.
//
// This command is equivalent to:
// nft rename chain (ip|ip6|inet|arp|bridge) {table_name} {old_chain_name} {new_chain_name}
Rename(family family.Type, tableName string, oldChainName string, newChainName string) error
}
-31
View File
@@ -1,31 +0,0 @@
package nft
import "git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
// Rule is the interface for rule manipulation.
type Rule interface {
// Add adds a new rule.
//
// This command is equivalent to:
// nft add rule (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ expr }'
Add(family family.Type, tableName string, chainName string, expr ...string) error
// Insert inserts a new rule.
// Inserted rules are placed at the beginning of the chain, by default.
//
// This command is equivalent to:
// nft insert rule (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ expr }'
Insert(family family.Type, tableName string, chainName string, expr ...string) error
// Replace replaces a rule.
//
// This command is equivalent to:
// nft replace rule (ip|ip6|inet|arp|bridge) {table_name} {chain_name} {handle} '{ expr }'
Replace(family family.Type, tableName string, chainName string, handle uint64, expr ...string) error
// Delete deletes a rule.
//
// This command is equivalent to:
// nft delete rule (ip|ip6|inet|arp|bridge) {table_name} {chain_name} {handle}
Delete(family family.Type, tableName string, chainName string, handle uint64) error
}
-24
View File
@@ -1,24 +0,0 @@
package nft
import "git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
// Table for working with tables.
type Table interface {
// AddTable adds a new table.
//
// This command is equivalent to:
// nft add table (ip|ip6|inet|arp|bridge) {table_name}
Add(family family.Type, tableName string) error
// DeleteTable deletes a table.
//
// This command is equivalent to:
// nft delete table (ip|ip6|inet|arp|bridge) {table_name}
Delete(family family.Type, tableName string) error
// ClearTable clears all rules in a table.
//
// This command is equivalent to:
// nft flush table (ip|ip6|inet|arp|bridge) {table_name}
Clear(family family.Type, tableName string) error
}
-8
View File
@@ -1,8 +0,0 @@
package nft
type Version interface {
// Version returns the version of the nftables client.
Version() string
// Opts returns the options of the nftables client.
Opts() map[string]string
}
-32
View File
@@ -1,32 +0,0 @@
package batch
import (
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/pkg"
)
type batch struct {
file *pkg.File
}
func NewBatch(file *pkg.File) contract.Batch {
return &batch{
file: file,
}
}
func (b *batch) Args() []string {
return []string{"-f", b.file.Path()}
}
func (b *batch) Check(command contract.Command) error {
return command.Run("-c", "-f", b.file.Path())
}
func (b *batch) Close() error {
return b.file.Remove()
}
func (b *batch) MoveFile(path string) error {
return b.file.Move(path)
}
-44
View File
@@ -1,44 +0,0 @@
package chain
import (
chain2 "git.kor-elf.net/kor-elf-shield/go-nftables-client/chain"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract/nft"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
nftCommand "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/pkg/nft"
)
type chain struct {
command contract.CommandRun
}
func New(command contract.CommandRun) nft.Chain {
return &chain{
command: command,
}
}
func (c *chain) Add(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) error {
args := nftCommand.ChainAdd(family, tableName, chainName, baseChain)
return c.command.Run(args...)
}
func (c *chain) Create(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) error {
args := nftCommand.ChainCreate(family, tableName, chainName, baseChain)
return c.command.Run(args...)
}
func (c *chain) Delete(family family.Type, tableName string, chainName string) error {
args := nftCommand.ChainDelete(family, tableName, chainName)
return c.command.Run(args...)
}
func (c *chain) Clear(family family.Type, tableName string, chainName string) error {
args := nftCommand.ChainClear(family, tableName, chainName)
return c.command.Run(args...)
}
func (c *chain) Rename(family family.Type, tableName string, oldChainName string, newChainName string) error {
args := nftCommand.ChainRename(family, tableName, oldChainName, newChainName)
return c.command.Run(args...)
}
-24
View File
@@ -1,24 +0,0 @@
package batch
import (
"fmt"
"strings"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/pkg"
)
type commandRun struct {
file *pkg.File
}
func NewCommand(file *pkg.File) contract.CommandRun {
return &commandRun{
file: file,
}
}
func (c *commandRun) Run(args ...string) error {
_, err := c.file.Write([]byte(fmt.Sprintf("%s\n", strings.Join(args, " "))))
return err
}
-38
View File
@@ -1,38 +0,0 @@
package rule
import (
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract/nft"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
nftCommand "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/pkg/nft"
)
type rule struct {
command contract.CommandRun
}
func New(command contract.CommandRun) nft.Rule {
return &rule{
command: command,
}
}
func (r *rule) Add(family family.Type, tableName string, chainName string, expr ...string) error {
args := nftCommand.RuleAdd(family, tableName, chainName, expr...)
return r.command.Run(args...)
}
func (r *rule) Insert(family family.Type, tableName string, chainName string, expr ...string) error {
args := nftCommand.RuleInsert(family, tableName, chainName, expr...)
return r.command.Run(args...)
}
func (r *rule) Replace(family family.Type, tableName string, chainName string, handle uint64, expr ...string) error {
args := nftCommand.RuleReplace(family, tableName, chainName, handle, expr...)
return r.command.Run(args...)
}
func (r *rule) Delete(family family.Type, tableName string, chainName string, handle uint64) error {
args := nftCommand.RuleDelete(family, tableName, chainName, handle)
return r.command.Run(args...)
}
-33
View File
@@ -1,33 +0,0 @@
package table
import (
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract/nft"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
nftCommand "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/pkg/nft"
)
type table struct {
command contract.CommandRun
}
func New(command contract.CommandRun) nft.Table {
return &table{
command: command,
}
}
func (t *table) Add(family family.Type, tableName string) error {
args := nftCommand.TableAdd(family, tableName)
return t.command.Run(args...)
}
func (t *table) Delete(family family.Type, tableName string) error {
args := nftCommand.TableDelete(family, tableName)
return t.command.Run(args...)
}
func (t *table) Clear(family family.Type, tableName string) error {
args := nftCommand.TableClear(family, tableName)
return t.command.Run(args...)
}
+49 -11
View File
@@ -2,43 +2,81 @@ package chain
import ( import (
chain2 "git.kor-elf.net/kor-elf-shield/go-nftables-client/chain" chain2 "git.kor-elf.net/kor-elf-shield/go-nftables-client/chain"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract/nft"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/family" "git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
nftCommand "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/pkg/nft" "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/command"
) )
type chain struct { // API for working with chains.
command contract.Command type API interface {
// Add adds a new chain.
//
// This command is equivalent to:
// nft add chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name}
// nft add chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type (filter|route|nat) hook (ingress|prerouting|forward|input|output|postrouting|egress) priority (priority_value = int32) ;}'
// nft add chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type filter hook (forward|input|output) priority (priority_value = int32) ; policy (accept|drop) ;}'
// nft add chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type (filter|route|nat) hook (ingress|egress) device {device} priority (priority_value = int32) ;}'
Add(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) error
// Create creates a new chain.
// Similar to the Add, but returns an error if the chain already exists.
//
// This command is equivalent to:
// nft create chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name}
// nft create chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type (filter|route|nat) hook (ingress|prerouting|forward|input|output|postrouting|egress) priority (priority_value = int32) ;}'
// nft create chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type filter hook (forward|input|output) priority (priority_value = int32) ; policy (accept|drop) ;}'
// nft create chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ type (filter|route|nat) hook (ingress|egress) device {device} priority (priority_value = int32) ;}'
Create(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) error
// Delete deletes a chain.
//
// This command is equivalent to:
// nft delete chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name}
Delete(family family.Type, tableName string, chainName string) error
// Clear clears all rules in a chain.
//
// This command is equivalent to:
// nft flush chain (ip|ip6|inet|arp|bridge) {table_name} {chain_name}
Clear(family family.Type, tableName string, chainName string) error
// Rename renames a chain.
//
// This command is equivalent to:
// nft rename chain (ip|ip6|inet|arp|bridge) {table_name} {old_chain_name} {new_chain_name}
Rename(family family.Type, tableName string, oldChainName string, newChainName string) error
} }
func New(command contract.Command) nft.Chain { type chain struct {
command command.NFT
}
func New(command command.NFT) API {
return &chain{ return &chain{
command: command, command: command,
} }
} }
func (c *chain) Add(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) error { func (c *chain) Add(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) error {
args := nftCommand.ChainAdd(family, tableName, chainName, baseChain) args := []string{"add", "chain", family.String(), tableName, chainName, baseChain.String()}
return c.command.Run(args...) return c.command.Run(args...)
} }
func (c *chain) Create(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) error { func (c *chain) Create(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) error {
args := nftCommand.ChainCreate(family, tableName, chainName, baseChain) args := []string{"create", "chain", family.String(), tableName, chainName, baseChain.String()}
return c.command.Run(args...) return c.command.Run(args...)
} }
func (c *chain) Delete(family family.Type, tableName string, chainName string) error { func (c *chain) Delete(family family.Type, tableName string, chainName string) error {
args := nftCommand.ChainDelete(family, tableName, chainName) args := []string{"delete", "chain", family.String(), tableName, chainName}
return c.command.Run(args...) return c.command.Run(args...)
} }
func (c *chain) Clear(family family.Type, tableName string, chainName string) error { func (c *chain) Clear(family family.Type, tableName string, chainName string) error {
args := nftCommand.ChainClear(family, tableName, chainName) args := []string{"flush", "chain", family.String(), tableName, chainName}
return c.command.Run(args...) return c.command.Run(args...)
} }
func (c *chain) Rename(family family.Type, tableName string, oldChainName string, newChainName string) error { func (c *chain) Rename(family family.Type, tableName string, oldChainName string, newChainName string) error {
args := nftCommand.ChainRename(family, tableName, oldChainName, newChainName) args := []string{"rename", "chain", family.String(), tableName, oldChainName, newChainName}
return c.command.Run(args...) return c.command.Run(args...)
} }
+9 -3
View File
@@ -3,15 +3,21 @@ package command
import ( import (
"errors" "errors"
"os/exec" "os/exec"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract"
) )
type NFT interface {
// Run nft command.
Run(arg ...string) error
// RunWithOutput Run nft command with output.
RunWithOutput(arg ...string) (string, error)
}
type execNFT struct { type execNFT struct {
nftPath string nftPath string
} }
func New(path string) (contract.Command, error) { func New(path string) (NFT, error) {
if err := checkingNFT(path); err != nil { if err := checkingNFT(path); err != nil {
return nil, err return nil, err
} }
-61
View File
@@ -1,61 +0,0 @@
package pkg
import (
"crypto/rand"
"fmt"
"os"
"path/filepath"
"time"
)
type File struct {
filepath string
file *os.File
isMoved bool
}
func CreateRandomTmpFile(dir string) (*File, error) {
if err := os.MkdirAll(dir, 0750); err != nil {
return nil, err
}
tmpFile := filepath.Join(dir, time.Now().Format(time.RFC3339)+"_"+rand.Text()+".tmp")
file, err := os.Create(tmpFile)
if err != nil {
return nil, err
}
return &File{
filepath: tmpFile,
file: file,
}, nil
}
func (f *File) Write(p []byte) (n int, err error) {
return f.file.Write(p)
}
func (f *File) Path() string {
return f.filepath
}
func (f *File) Remove() error {
if f.isMoved {
return nil
}
return os.Remove(f.filepath)
}
func (f *File) Move(path string) error {
if f.isMoved {
return fmt.Errorf("file already moved")
}
if err := os.Rename(f.filepath, path); err != nil {
return err
}
f.isMoved = true
return nil
}
-26
View File
@@ -1,26 +0,0 @@
package nft
import (
chain2 "git.kor-elf.net/kor-elf-shield/go-nftables-client/chain"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
)
func ChainAdd(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) []string {
return []string{"add", "chain", family.String(), tableName, chainName, baseChain.String()}
}
func ChainCreate(family family.Type, tableName string, chainName string, baseChain chain2.ChainOptions) []string {
return []string{"create", "chain", family.String(), tableName, chainName, baseChain.String()}
}
func ChainDelete(family family.Type, tableName string, chainName string) []string {
return []string{"delete", "chain", family.String(), tableName, chainName}
}
func ChainClear(family family.Type, tableName string, chainName string) []string {
return []string{"flush", "chain", family.String(), tableName, chainName}
}
func ChainRename(family family.Type, tableName string, oldChainName string, newChainName string) []string {
return []string{"rename", "chain", family.String(), tableName, oldChainName, newChainName}
}
-5
View File
@@ -1,5 +0,0 @@
package nft
func Clear() []string {
return []string{"flush", "ruleset"}
}
-30
View File
@@ -1,30 +0,0 @@
package nft
import (
"strconv"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
)
func RuleAdd(family family.Type, tableName string, chainName string, expr ...string) []string {
args := []string{"add", "rule", family.String(), tableName, chainName}
args = append(args, expr...)
return args
}
func RuleInsert(family family.Type, tableName string, chainName string, expr ...string) []string {
args := []string{"insert", "rule", family.String(), tableName, chainName}
args = append(args, expr...)
return args
}
func RuleReplace(family family.Type, tableName string, chainName string, handle uint64, expr ...string) []string {
args := []string{"replace", "rule", family.String(), tableName, chainName, "handle", strconv.Itoa(int(handle))}
args = append(args, expr...)
return args
}
func RuleDelete(family family.Type, tableName string, chainName string, handle uint64) []string {
args := []string{"delete", "rule", family.String(), tableName, chainName, "handle", strconv.Itoa(int(handle))}
return args
}
-15
View File
@@ -1,15 +0,0 @@
package nft
import "git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
func TableAdd(family family.Type, tableName string) []string {
return []string{"add", "table", family.String(), tableName}
}
func TableDelete(family family.Type, tableName string) []string {
return []string{"delete", "table", family.String(), tableName}
}
func TableClear(family family.Type, tableName string) []string {
return []string{"flush", "table", family.String(), tableName}
}
+40 -10
View File
@@ -1,38 +1,68 @@
package rule package rule
import ( import (
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract" "strconv"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract/nft"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/family" "git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
nftCommand "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/pkg/nft" "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/command"
) )
type rule struct { type API interface {
command contract.Command // Add adds a new rule.
//
// This command is equivalent to:
// nft add rule (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ expr }'
Add(family family.Type, tableName string, chainName string, expr ...string) error
// Insert inserts a new rule.
// Inserted rules are placed at the beginning of the chain, by default.
//
// This command is equivalent to:
// nft insert rule (ip|ip6|inet|arp|bridge) {table_name} {chain_name} '{ expr }'
Insert(family family.Type, tableName string, chainName string, expr ...string) error
// Replace replaces a rule.
//
// This command is equivalent to:
// nft replace rule (ip|ip6|inet|arp|bridge) {table_name} {chain_name} {handle} '{ expr }'
Replace(family family.Type, tableName string, chainName string, handle uint64, expr ...string) error
// Delete deletes a rule.
//
// This command is equivalent to:
// nft delete rule (ip|ip6|inet|arp|bridge) {table_name} {chain_name} {handle}
Delete(family family.Type, tableName string, chainName string, handle uint64) error
} }
func New(command contract.Command) nft.Rule { type rule struct {
command command.NFT
}
func New(command command.NFT) API {
return &rule{ return &rule{
command: command, command: command,
} }
} }
func (r *rule) Add(family family.Type, tableName string, chainName string, expr ...string) error { func (r *rule) Add(family family.Type, tableName string, chainName string, expr ...string) error {
args := nftCommand.RuleAdd(family, tableName, chainName, expr...) args := []string{"add", "rule", family.String(), tableName, chainName}
args = append(args, expr...)
return r.command.Run(args...) return r.command.Run(args...)
} }
func (r *rule) Insert(family family.Type, tableName string, chainName string, expr ...string) error { func (r *rule) Insert(family family.Type, tableName string, chainName string, expr ...string) error {
args := nftCommand.RuleInsert(family, tableName, chainName, expr...) args := []string{"insert", "rule", family.String(), tableName, chainName}
args = append(args, expr...)
return r.command.Run(args...) return r.command.Run(args...)
} }
func (r *rule) Replace(family family.Type, tableName string, chainName string, handle uint64, expr ...string) error { func (r *rule) Replace(family family.Type, tableName string, chainName string, handle uint64, expr ...string) error {
args := nftCommand.RuleReplace(family, tableName, chainName, handle, expr...) args := []string{"replace", "rule", family.String(), tableName, chainName, "handle", strconv.Itoa(int(handle))}
args = append(args, expr...)
return r.command.Run(args...) return r.command.Run(args...)
} }
func (r *rule) Delete(family family.Type, tableName string, chainName string, handle uint64) error { func (r *rule) Delete(family family.Type, tableName string, chainName string, handle uint64) error {
args := nftCommand.RuleDelete(family, tableName, chainName, handle) args := []string{"delete", "rule", family.String(), tableName, chainName, "handle", strconv.Itoa(int(handle))}
return r.command.Run(args...) return r.command.Run(args...)
} }
+28 -9
View File
@@ -1,33 +1,52 @@
package table package table
import ( import (
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract/nft"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/family" "git.kor-elf.net/kor-elf-shield/go-nftables-client/family"
nftCommand "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/pkg/nft" "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/command"
) )
type table struct { // API for working with tables.
command contract.Command type API interface {
// AddTable adds a new table.
//
// This command is equivalent to:
// nft add table (ip|ip6|inet|arp|bridge) {table_name}
Add(family family.Type, tableName string) error
// DeleteTable deletes a table.
//
// This command is equivalent to:
// nft delete table (ip|ip6|inet|arp|bridge) {table_name}
Delete(family family.Type, tableName string) error
// ClearTable clears all rules in a table.
//
// This command is equivalent to:
// nft flush table (ip|ip6|inet|arp|bridge) {table_name}
Clear(family family.Type, tableName string) error
} }
func New(command contract.Command) nft.Table { type table struct {
command command.NFT
}
func New(command command.NFT) API {
return &table{ return &table{
command: command, command: command,
} }
} }
func (t *table) Add(family family.Type, tableName string) error { func (t *table) Add(family family.Type, tableName string) error {
args := nftCommand.TableAdd(family, tableName) args := []string{"add", "table", family.String(), tableName}
return t.command.Run(args...) return t.command.Run(args...)
} }
func (t *table) Delete(family family.Type, tableName string) error { func (t *table) Delete(family family.Type, tableName string) error {
args := nftCommand.TableDelete(family, tableName) args := []string{"delete", "table", family.String(), tableName}
return t.command.Run(args...) return t.command.Run(args...)
} }
func (t *table) Clear(family family.Type, tableName string) error { func (t *table) Clear(family family.Type, tableName string) error {
args := nftCommand.TableClear(family, tableName) args := []string{"flush", "table", family.String(), tableName}
return t.command.Run(args...) return t.command.Run(args...)
} }
+40 -26
View File
@@ -5,25 +5,50 @@ import (
"regexp" "regexp"
"strings" "strings"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/contract"
nftContract "git.kor-elf.net/kor-elf-shield/go-nftables-client/contract/nft"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/chain" "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/chain"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/command" "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/command"
nftCommand "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/pkg/nft"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/rule" "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/rule"
"git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/table" "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/table"
) )
// NFT A client for working with nftables
type NFT interface {
// Command returns the command used to execute nft.
// You can execute your raw request.
Command() command.NFT
// Clear clears all rules.
//
// This command is equivalent to:
// nft flush ruleset
Clear() error
// Version returns the version of nftables.
//
// This command is equivalent to:
// nft -V
Version() (Version, error)
// Table returns an API for working with tables.
Table() table.API
// Chain returns an API for working with chains.
Chain() chain.API
// Rule returns an API for working with rules.
Rule() rule.API
}
type nft struct { type nft struct {
command contract.Command command command.NFT
table nftContract.Table table table.API
chain nftContract.Chain chain chain.API
rule nftContract.Rule rule rule.API
} }
// New Returns a client for working with nftables. // New Returns a client for working with nftables.
// Searches for nft in paths: nft, /usr/sbin/nft, /sbin/nft // Searches for nft in paths: nft, /usr/sbin/nft, /sbin/nft
func New() (contract.NFT, error) { func New() (NFT, error) {
paths := []string{"nft", "/usr/sbin/nft", "/sbin/nft"} paths := []string{"nft", "/usr/sbin/nft", "/sbin/nft"}
for _, path := range paths { for _, path := range paths {
nftClient, err := NewWithPath(path) nftClient, err := NewWithPath(path)
@@ -36,7 +61,7 @@ func New() (contract.NFT, error) {
} }
// NewWithPath Returns the client for working with nftables with its path specified. // NewWithPath Returns the client for working with nftables with its path specified.
func NewWithPath(path string) (contract.NFT, error) { func NewWithPath(path string) (NFT, error) {
nftCommand, err := command.New(path) nftCommand, err := command.New(path)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -51,11 +76,11 @@ func NewWithPath(path string) (contract.NFT, error) {
} }
func (n *nft) Clear() error { func (n *nft) Clear() error {
args := nftCommand.Clear() args := []string{"flush", "ruleset"}
return n.command.Run(args...) return n.command.Run(args...)
} }
func (n *nft) Version() (nftContract.Version, error) { func (n *nft) Version() (Version, error) {
args := []string{"-V"} args := []string{"-V"}
out, err := n.command.RunWithOutput(args...) out, err := n.command.RunWithOutput(args...)
if err != nil { if err != nil {
@@ -89,29 +114,18 @@ func (n *nft) Version() (nftContract.Version, error) {
}, nil }, nil
} }
func (n *nft) Table() nftContract.Table { func (n *nft) Table() table.API {
return n.table return n.table
} }
func (n *nft) Chain() nftContract.Chain { func (n *nft) Chain() chain.API {
return n.chain return n.chain
} }
func (n *nft) Rule() nftContract.Rule { func (n *nft) Rule() rule.API {
return n.rule return n.rule
} }
func (n *nft) Command() contract.Command { func (n *nft) Command() command.NFT {
return n.command return n.command
} }
func (n *nft) ExecuteBatchAfterCheck(batch contract.Batch) error {
if err := batch.Check(n.command); err != nil {
return err
}
return n.command.Run(batch.Args()...)
}
func (n *nft) ExecuteBatch(batch contract.Batch) error {
return n.command.Run(batch.Args()...)
}
+9 -2
View File
@@ -1,14 +1,21 @@
package nft package nft
type Version interface {
// Version returns the version of the nftables client.
Version() string
// Opts returns the options of the nftables client.
Opts() map[string]string
}
type version struct { type version struct {
version string version string
opts map[string]string opts map[string]string
} }
func (v *version) Version() string { func (v version) Version() string {
return v.version return v.version
} }
func (v *version) Opts() map[string]string { func (v version) Opts() map[string]string {
return v.opts return v.opts
} }