Compare commits
6 Commits
4865155073
...
ac1a18a304
Author | SHA1 | Date | |
---|---|---|---|
ac1a18a304 | |||
1cbb831f4d | |||
a2b024e006 | |||
69b776caea | |||
9ff67c6b84 | |||
f4d83e2ebe |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.idea/
|
104
README.md
Normal file
104
README.md
Normal file
@ -0,0 +1,104 @@
|
||||
# ifupdown
|
||||
|
||||
[![GoDoc](https://godoc.org/git.tcp.direct/kayos/ifupdown?status.svg)](https://godoc.org/git.tcp.direct/kayos/ifupdown)
|
||||
|
||||
|
||||
golang library for working with network interfaces defined via [ifupdown](https://manpages.debian.org/jessie/ifupdown/interfaces.5.en.html).
|
||||
commonly recognized as `/etc/network/interfaces`.
|
||||
|
||||
## library
|
||||
|
||||
### features
|
||||
|
||||
- [x] read+parse interfaces file
|
||||
- [x] write interfaces file
|
||||
- [x] validate interfaces file (basic)
|
||||
- [ ] validate interfaces file (thorough)
|
||||
- [x] translate interfaces file to JSON
|
||||
- [x] translate JSON to interfaces file
|
||||
|
||||
## cmd
|
||||
|
||||
- `ifup2json` - translate interfaces file to JSON
|
||||
- `json2ifup` - translate JSON to interfaces file
|
||||
|
||||
### example usage
|
||||
|
||||
<details>
|
||||
<summary>ifup2json</summary>
|
||||
|
||||
`cat /etc/network/interfaces | ifup2json`
|
||||
|
||||
```json
|
||||
{
|
||||
"eth2": {
|
||||
"name": "eth2",
|
||||
"auto": true,
|
||||
"address": "192.168.69.5",
|
||||
"netmask": "////AA==",
|
||||
"gateway": "192.168.69.1",
|
||||
"config": 3,
|
||||
"version": 1,
|
||||
"hooks": {
|
||||
"pre_up": [
|
||||
"echo yeet"
|
||||
],
|
||||
"post_down": [
|
||||
"echo yeeted"
|
||||
]
|
||||
}
|
||||
},
|
||||
"lo": {
|
||||
"name": "lo",
|
||||
"auto": true,
|
||||
"config": 1,
|
||||
"version": 1,
|
||||
"hooks": {}
|
||||
},
|
||||
"ns3": {
|
||||
"name": "ns3",
|
||||
"auto": true,
|
||||
"address": "10.9.0.6",
|
||||
"netmask": "////AAAAAAAAAAAAAAAAAA==",
|
||||
"config": 3,
|
||||
"version": 1,
|
||||
"hooks": {
|
||||
"pre_up": [
|
||||
"ip link add dev ns3 type wireguard"
|
||||
],
|
||||
"post_up": [
|
||||
"wg setconf ns3 /etc/wireguard/ns3.conf"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>json2ifup</summary>
|
||||
|
||||
`cat /etc/network/interfaces | ifup2json | json2ifup`
|
||||
|
||||
```
|
||||
auto eth2
|
||||
iface eth2 inet static
|
||||
address 192.168.69.5
|
||||
netmask 255.255.255.0
|
||||
gateway 192.168.69.1
|
||||
pre-up echo yeet
|
||||
post-down echo yeeted
|
||||
|
||||
auto lo
|
||||
iface lo inet loopback
|
||||
|
||||
auto ns3
|
||||
iface ns3 inet static
|
||||
address 10.9.0.6
|
||||
netmask 255.255.255.0
|
||||
pre-up ip link add dev ns3 type wireguard
|
||||
post-up wg setconf ns3 /etc/wireguard/ns3.conf
|
||||
```
|
||||
|
||||
</details>
|
68
cmd/json2ifup/main.go
Normal file
68
cmd/json2ifup/main.go
Normal file
@ -0,0 +1,68 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
iface "git.tcp.direct/kayos/ifupdown"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var ifaces = make(iface.Interfaces)
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
switch {
|
||||
case len(os.Args) < 2:
|
||||
var empty = 0
|
||||
for {
|
||||
n, err := buf.ReadFrom(os.Stdin)
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if n == 0 {
|
||||
empty++
|
||||
}
|
||||
if empty > 100 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
f, err := os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
_, _ = buf.ReadFrom(f)
|
||||
}
|
||||
err := json.Unmarshal(buf.Bytes(), &ifaces)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
// println("input received: " + string(buf.Bytes()))
|
||||
return
|
||||
}
|
||||
|
||||
for name, netif := range ifaces {
|
||||
if netif == nil {
|
||||
delete(ifaces, name)
|
||||
continue
|
||||
}
|
||||
if netif.Name != name {
|
||||
panic("name mismatch")
|
||||
}
|
||||
if err = netif.Validate(); err != nil {
|
||||
println(name + ": skip due to error: " + err.Error())
|
||||
delete(ifaces, name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = os.Stdout.WriteString(ifaces.String()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package iface
|
||||
package ifupdown
|
||||
|
||||
import "errors"
|
||||
|
||||
|
44
ifaces.go
44
ifaces.go
@ -1,8 +1,11 @@
|
||||
package iface
|
||||
package ifupdown
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@ -11,12 +14,43 @@ import (
|
||||
|
||||
type Interfaces map[string]*NetworkInterface
|
||||
|
||||
type poolGroup struct {
|
||||
Buffers pool.BufferFactory
|
||||
Strs pool.StringFactory
|
||||
func (i Interfaces) buf() *pool.Buffer {
|
||||
buf := pools.Buffers.Get()
|
||||
for _, iface := range i {
|
||||
err := iface.write(func(s string) { buf.MustWrite([]byte(s)) })
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
panic(err)
|
||||
}
|
||||
buf.MustWrite([]byte("\n"))
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
var pools = poolGroup{Buffers: pool.NewBufferFactory(), Strs: pool.NewStringFactory()}
|
||||
func (i Interfaces) Read(p []byte) (int, error) {
|
||||
buf := i.buf()
|
||||
defer pools.Buffers.MustPut(buf)
|
||||
return buf.Read(p)
|
||||
}
|
||||
|
||||
func (i Interfaces) String() string {
|
||||
buf := i.buf()
|
||||
defer pools.Buffers.MustPut(buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (i Interfaces) UnmarshalJSON(data []byte) error {
|
||||
var ifaces map[string]*NetworkInterface
|
||||
if err := json.Unmarshal(data, &ifaces); err != nil {
|
||||
return err
|
||||
}
|
||||
for name, iface := range ifaces {
|
||||
iface.Name = name
|
||||
iface.allocated = true
|
||||
i[name] = iface
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type MultiParser struct {
|
||||
Interfaces map[string]*NetworkInterface
|
||||
|
@ -1,4 +1,4 @@
|
||||
package iface
|
||||
package ifupdown
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@ -19,7 +19,8 @@ iface eth0 inet dhcp
|
||||
t.Fatalf("Write failed: %v", err)
|
||||
}
|
||||
|
||||
err = mp.Parse()
|
||||
var ifaces Interfaces
|
||||
ifaces, err = mp.Parse()
|
||||
if err != nil {
|
||||
t.Fatalf("Expected nil error, got: %v", err)
|
||||
}
|
||||
@ -28,6 +29,10 @@ iface eth0 inet dhcp
|
||||
t.Fatalf("Expected 2 interfaces, got: %d", len(mp.Interfaces))
|
||||
}
|
||||
|
||||
if len(mp.Interfaces) != len(ifaces) {
|
||||
t.Fatalf("Expected %d interfaces, got: %d", len(mp.Interfaces), len(ifaces))
|
||||
}
|
||||
|
||||
loIface, ok := mp.Interfaces["lo"]
|
||||
if !ok || loIface.Name != "lo" {
|
||||
t.Fatalf("Expected to find interface 'lo', got: %+v", loIface)
|
||||
@ -37,6 +42,11 @@ iface eth0 inet dhcp
|
||||
if !ok || eth0Iface.Name != "eth0" {
|
||||
t.Fatalf("Expected to find interface 'eth0', got: %+v", eth0Iface)
|
||||
}
|
||||
for _, iface := range ifaces {
|
||||
if err = iface.Validate(); err != nil {
|
||||
t.Fatalf("Expected nil error, got: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add more test functions here to check other aspects and edge cases.
|
||||
|
5
netif.go
5
netif.go
@ -1,4 +1,4 @@
|
||||
package iface
|
||||
package ifupdown
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
@ -110,9 +110,10 @@ func (iface *NetworkInterface) allocate() {
|
||||
if iface.RWMutex == nil {
|
||||
iface.RWMutex = &sync.RWMutex{}
|
||||
}
|
||||
iface.Lock()
|
||||
iface.Lock() // gets unlocked in other methods
|
||||
iface.dirty = true
|
||||
iface.allocated = true
|
||||
|
||||
}
|
||||
|
||||
func (iface *NetworkInterface) err() error {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package iface
|
||||
package ifupdown
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
10
util.go
Normal file
10
util.go
Normal file
@ -0,0 +1,10 @@
|
||||
package ifupdown
|
||||
|
||||
import "git.tcp.direct/kayos/common/pool"
|
||||
|
||||
type poolGroup struct {
|
||||
Buffers pool.BufferFactory
|
||||
Strs pool.StringFactory
|
||||
}
|
||||
|
||||
var pools = poolGroup{Buffers: pool.NewBufferFactory(), Strs: pool.NewStringFactory()}
|
Loading…
Reference in New Issue
Block a user