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"
|
import "errors"
|
||||||
|
|
||||||
|
44
ifaces.go
44
ifaces.go
@ -1,8 +1,11 @@
|
|||||||
package iface
|
package ifupdown
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@ -11,12 +14,43 @@ import (
|
|||||||
|
|
||||||
type Interfaces map[string]*NetworkInterface
|
type Interfaces map[string]*NetworkInterface
|
||||||
|
|
||||||
type poolGroup struct {
|
func (i Interfaces) buf() *pool.Buffer {
|
||||||
Buffers pool.BufferFactory
|
buf := pools.Buffers.Get()
|
||||||
Strs pool.StringFactory
|
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 {
|
type MultiParser struct {
|
||||||
Interfaces map[string]*NetworkInterface
|
Interfaces map[string]*NetworkInterface
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package iface
|
package ifupdown
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
@ -19,7 +19,8 @@ iface eth0 inet dhcp
|
|||||||
t.Fatalf("Write failed: %v", err)
|
t.Fatalf("Write failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mp.Parse()
|
var ifaces Interfaces
|
||||||
|
ifaces, err = mp.Parse()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Expected nil error, got: %v", err)
|
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))
|
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"]
|
loIface, ok := mp.Interfaces["lo"]
|
||||||
if !ok || loIface.Name != "lo" {
|
if !ok || loIface.Name != "lo" {
|
||||||
t.Fatalf("Expected to find interface 'lo', got: %+v", loIface)
|
t.Fatalf("Expected to find interface 'lo', got: %+v", loIface)
|
||||||
@ -37,6 +42,11 @@ iface eth0 inet dhcp
|
|||||||
if !ok || eth0Iface.Name != "eth0" {
|
if !ok || eth0Iface.Name != "eth0" {
|
||||||
t.Fatalf("Expected to find interface 'eth0', got: %+v", eth0Iface)
|
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.
|
// 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 (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@ -110,9 +110,10 @@ func (iface *NetworkInterface) allocate() {
|
|||||||
if iface.RWMutex == nil {
|
if iface.RWMutex == nil {
|
||||||
iface.RWMutex = &sync.RWMutex{}
|
iface.RWMutex = &sync.RWMutex{}
|
||||||
}
|
}
|
||||||
iface.Lock()
|
iface.Lock() // gets unlocked in other methods
|
||||||
iface.dirty = true
|
iface.dirty = true
|
||||||
iface.allocated = true
|
iface.allocated = true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *NetworkInterface) err() error {
|
func (iface *NetworkInterface) err() error {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package iface
|
package ifupdown
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"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