mirror of
https://github.com/slackhq/nebula.git
synced 2025-11-23 00:44:25 +01:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a800a48857 | ||
|
|
4c0ae3df5e | ||
|
|
feb3e1317f | ||
|
|
c2259f14a7 | ||
|
|
b1eeb5f3b8 | ||
|
|
2adf0ca1d1 |
57
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
57
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
name: "\U0001F41B Bug Report"
|
||||||
|
description: Report an issue or possible bug
|
||||||
|
title: "\U0001F41B BUG:"
|
||||||
|
labels: []
|
||||||
|
assignees: []
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
### Thank you for taking the time to file a bug report!
|
||||||
|
|
||||||
|
Please fill out this form as completely as possible.
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: What version of `nebula` are you using?
|
||||||
|
placeholder: 0.0.0
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: os
|
||||||
|
attributes:
|
||||||
|
label: What operating system are you using?
|
||||||
|
description: iOS and Android specific issues belong in the [mobile_nebula](https://github.com/DefinedNet/mobile_nebula) repo.
|
||||||
|
placeholder: Linux, Mac, Windows
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Describe the Bug
|
||||||
|
description: A clear and concise description of what the bug is.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Logs from affected hosts
|
||||||
|
description: |
|
||||||
|
Provide logs from all affected hosts during the time of the issue.
|
||||||
|
Improve formatting by using <code>```</code> at the beginning and end of each log block.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: configs
|
||||||
|
attributes:
|
||||||
|
label: Config files from affected hosts
|
||||||
|
description: |
|
||||||
|
Provide config files for all affected hosts.
|
||||||
|
Improve formatting by using <code>```</code> at the beginning and end of each config file.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
9
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
9
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
blank_issues_enabled: true
|
||||||
|
contact_links:
|
||||||
|
- name: 📘 Documentation
|
||||||
|
url: https://www.defined.net/nebula/
|
||||||
|
about: Review documentation.
|
||||||
|
|
||||||
|
- name: 💁 Support/Chat
|
||||||
|
url: https://join.slack.com/t/nebulaoss/shared_invite/enQtOTA5MDI4NDg3MTg4LTkwY2EwNTI4NzQyMzc0M2ZlODBjNWI3NTY1MzhiOThiMmZlZjVkMTI0NGY4YTMyNjUwMWEyNzNkZTJmYzQxOGU
|
||||||
|
about: 'This issue tracker is not for support questions. Join us on Slack for assistance!'
|
||||||
16
CHANGELOG.md
16
CHANGELOG.md
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [1.6.1] - 2022-09-26
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Refuse to process underlay packets received from overlay IPs. This prevents
|
||||||
|
confusion on hosts that have unsafe routes configured. (#741)
|
||||||
|
|
||||||
|
- The ssh `reload` command did not work on Windows, since it relied on sending
|
||||||
|
a SIGHUP signal internally. This has been fixed. (#725)
|
||||||
|
|
||||||
|
- A regression in v1.5.2 that broke unsafe routes on Mobile clients has been
|
||||||
|
fixed. (#729)
|
||||||
|
|
||||||
## [1.6.0] - 2022-06-30
|
## [1.6.0] - 2022-06-30
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@@ -385,7 +398,8 @@ created.)
|
|||||||
|
|
||||||
- Initial public release.
|
- Initial public release.
|
||||||
|
|
||||||
[Unreleased]: https://github.com/slackhq/nebula/compare/v1.6.0...HEAD
|
[Unreleased]: https://github.com/slackhq/nebula/compare/v1.6.1...HEAD
|
||||||
|
[1.6.1]: https://github.com/slackhq/nebula/releases/tag/v1.6.1
|
||||||
[1.6.0]: https://github.com/slackhq/nebula/releases/tag/v1.6.0
|
[1.6.0]: https://github.com/slackhq/nebula/releases/tag/v1.6.0
|
||||||
[1.5.2]: https://github.com/slackhq/nebula/releases/tag/v1.5.2
|
[1.5.2]: https://github.com/slackhq/nebula/releases/tag/v1.5.2
|
||||||
[1.5.0]: https://github.com/slackhq/nebula/releases/tag/v1.5.0
|
[1.5.0]: https://github.com/slackhq/nebula/releases/tag/v1.5.0
|
||||||
|
|||||||
3
Makefile
3
Makefile
@@ -66,6 +66,9 @@ e2evvv: e2ev
|
|||||||
e2evvvv: TEST_ENV += TEST_LOGS=3
|
e2evvvv: TEST_ENV += TEST_LOGS=3
|
||||||
e2evvvv: e2ev
|
e2evvvv: e2ev
|
||||||
|
|
||||||
|
e2e-bench: TEST_FLAGS = -bench=. -benchmem -run=^$
|
||||||
|
e2e-bench: e2e
|
||||||
|
|
||||||
all: $(ALL:%=build/%/nebula) $(ALL:%=build/%/nebula-cert)
|
all: $(ALL:%=build/%/nebula) $(ALL:%=build/%/nebula-cert)
|
||||||
|
|
||||||
release: $(ALL:%=build/nebula-%.tar.gz)
|
release: $(ALL:%=build/nebula-%.tar.gz)
|
||||||
|
|||||||
@@ -16,6 +16,30 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func BenchmarkHotPath(b *testing.B) {
|
||||||
|
ca, _, caKey, _ := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})
|
||||||
|
myControl, _, _ := newSimpleServer(ca, caKey, "me", net.IP{10, 0, 0, 1}, nil)
|
||||||
|
theirControl, theirVpnIp, theirUdpAddr := newSimpleServer(ca, caKey, "them", net.IP{10, 0, 0, 2}, nil)
|
||||||
|
|
||||||
|
// Put their info in our lighthouse
|
||||||
|
myControl.InjectLightHouseAddr(theirVpnIp, theirUdpAddr)
|
||||||
|
|
||||||
|
// Start the servers
|
||||||
|
myControl.Start()
|
||||||
|
theirControl.Start()
|
||||||
|
|
||||||
|
r := router.NewR(b, myControl, theirControl)
|
||||||
|
r.CancelFlowLogs()
|
||||||
|
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
myControl.InjectTunUDPPacket(theirVpnIp, 80, 80, []byte("Hi from me"))
|
||||||
|
_ = r.RouteForAllUntilTxTun(theirControl)
|
||||||
|
}
|
||||||
|
|
||||||
|
myControl.Stop()
|
||||||
|
theirControl.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
func TestGoodHandshake(t *testing.T) {
|
func TestGoodHandshake(t *testing.T) {
|
||||||
ca, _, caKey, _ := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})
|
ca, _, caKey, _ := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})
|
||||||
myControl, myVpnIp, myUdpAddr := newSimpleServer(ca, caKey, "me", net.IP{10, 0, 0, 1}, nil)
|
myControl, myVpnIp, myUdpAddr := newSimpleServer(ca, caKey, "me", net.IP{10, 0, 0, 1}, nil)
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -304,7 +303,8 @@ func NewTestLogger() *logrus.Logger {
|
|||||||
|
|
||||||
v := os.Getenv("TEST_LOGS")
|
v := os.Getenv("TEST_LOGS")
|
||||||
if v == "" {
|
if v == "" {
|
||||||
l.SetOutput(ioutil.Discard)
|
l.SetOutput(io.Discard)
|
||||||
|
l.SetLevel(logrus.PanicLevel)
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ type R struct {
|
|||||||
|
|
||||||
fn string
|
fn string
|
||||||
cancelRender context.CancelFunc
|
cancelRender context.CancelFunc
|
||||||
t *testing.T
|
t testing.TB
|
||||||
}
|
}
|
||||||
|
|
||||||
type flowEntry struct {
|
type flowEntry struct {
|
||||||
@@ -63,6 +63,12 @@ type packet struct {
|
|||||||
rx bool // the packet was received by a udp device
|
rx bool // the packet was received by a udp device
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *packet) WasReceived() {
|
||||||
|
if p != nil {
|
||||||
|
p.rx = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ExitType int
|
type ExitType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -79,7 +85,7 @@ type ExitFunc func(packet *udp.Packet, receiver *nebula.Control) ExitType
|
|||||||
// NewR creates a new router to pass packets in a controlled fashion between the provided controllers.
|
// NewR creates a new router to pass packets in a controlled fashion between the provided controllers.
|
||||||
// The packet flow will be recorded in a file within the mermaid directory under the same name as the test.
|
// The packet flow will be recorded in a file within the mermaid directory under the same name as the test.
|
||||||
// Renders will occur automatically, roughly every 100ms, until a call to RenderFlow() is made
|
// Renders will occur automatically, roughly every 100ms, until a call to RenderFlow() is made
|
||||||
func NewR(t *testing.T, controls ...*nebula.Control) *R {
|
func NewR(t testing.TB, controls ...*nebula.Control) *R {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
if err := os.MkdirAll("mermaid", 0755); err != nil {
|
if err := os.MkdirAll("mermaid", 0755); err != nil {
|
||||||
@@ -91,6 +97,7 @@ func NewR(t *testing.T, controls ...*nebula.Control) *R {
|
|||||||
vpnControls: make(map[iputil.VpnIp]*nebula.Control),
|
vpnControls: make(map[iputil.VpnIp]*nebula.Control),
|
||||||
inNat: make(map[string]*nebula.Control),
|
inNat: make(map[string]*nebula.Control),
|
||||||
outNat: make(map[string]net.UDPAddr),
|
outNat: make(map[string]net.UDPAddr),
|
||||||
|
flow: []flowEntry{},
|
||||||
fn: filepath.Join("mermaid", fmt.Sprintf("%s.md", t.Name())),
|
fn: filepath.Join("mermaid", fmt.Sprintf("%s.md", t.Name())),
|
||||||
t: t,
|
t: t,
|
||||||
cancelRender: cancel,
|
cancelRender: cancel,
|
||||||
@@ -148,14 +155,24 @@ func (r *R) RenderFlow() {
|
|||||||
r.renderFlow()
|
r.renderFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CancelFlowLogs stops flow logs from being tracked and destroys any logs already collected
|
||||||
|
func (r *R) CancelFlowLogs() {
|
||||||
|
r.cancelRender()
|
||||||
|
r.flow = nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *R) renderFlow() {
|
func (r *R) renderFlow() {
|
||||||
|
if r.flow == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
f, err := os.OpenFile(r.fn, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0644)
|
f, err := os.OpenFile(r.fn, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var participants = map[string]struct{}{}
|
var participants = map[string]struct{}{}
|
||||||
var participansVals []string
|
var participantsVals []string
|
||||||
|
|
||||||
fmt.Fprintln(f, "```mermaid")
|
fmt.Fprintln(f, "```mermaid")
|
||||||
fmt.Fprintln(f, "sequenceDiagram")
|
fmt.Fprintln(f, "sequenceDiagram")
|
||||||
@@ -172,7 +189,7 @@ func (r *R) renderFlow() {
|
|||||||
}
|
}
|
||||||
participants[addr] = struct{}{}
|
participants[addr] = struct{}{}
|
||||||
sanAddr := strings.Replace(addr, ":", "#58;", 1)
|
sanAddr := strings.Replace(addr, ":", "#58;", 1)
|
||||||
participansVals = append(participansVals, sanAddr)
|
participantsVals = append(participantsVals, sanAddr)
|
||||||
fmt.Fprintf(
|
fmt.Fprintf(
|
||||||
f, " participant %s as Nebula: %s<br/>UDP: %s\n",
|
f, " participant %s as Nebula: %s<br/>UDP: %s\n",
|
||||||
sanAddr, e.packet.from.GetVpnIp(), sanAddr,
|
sanAddr, e.packet.from.GetVpnIp(), sanAddr,
|
||||||
@@ -183,7 +200,7 @@ func (r *R) renderFlow() {
|
|||||||
h := &header.H{}
|
h := &header.H{}
|
||||||
for _, e := range r.flow {
|
for _, e := range r.flow {
|
||||||
if e.packet == nil {
|
if e.packet == nil {
|
||||||
fmt.Fprintf(f, " note over %s: %s\n", strings.Join(participansVals, ", "), e.note)
|
fmt.Fprintf(f, " note over %s: %s\n", strings.Join(participantsVals, ", "), e.note)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,6 +239,10 @@ func (r *R) InjectFlow(from, to *nebula.Control, p *udp.Packet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *R) Log(arg ...any) {
|
func (r *R) Log(arg ...any) {
|
||||||
|
if r.flow == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r.Lock()
|
r.Lock()
|
||||||
r.flow = append(r.flow, flowEntry{note: fmt.Sprint(arg...)})
|
r.flow = append(r.flow, flowEntry{note: fmt.Sprint(arg...)})
|
||||||
r.t.Log(arg...)
|
r.t.Log(arg...)
|
||||||
@@ -229,6 +250,10 @@ func (r *R) Log(arg ...any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *R) Logf(format string, arg ...any) {
|
func (r *R) Logf(format string, arg ...any) {
|
||||||
|
if r.flow == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r.Lock()
|
r.Lock()
|
||||||
r.flow = append(r.flow, flowEntry{note: fmt.Sprintf(format, arg...)})
|
r.flow = append(r.flow, flowEntry{note: fmt.Sprintf(format, arg...)})
|
||||||
r.t.Logf(format, arg...)
|
r.t.Logf(format, arg...)
|
||||||
@@ -236,14 +261,20 @@ func (r *R) Logf(format string, arg ...any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// unlockedInjectFlow is used by the router to record a packet has been transmitted, the packet is returned and
|
// unlockedInjectFlow is used by the router to record a packet has been transmitted, the packet is returned and
|
||||||
// should be marked as received AFTER it has been placed on the receivers channel
|
// should be marked as received AFTER it has been placed on the receivers channel.
|
||||||
|
// If flow logs have been disabled this function will return nil
|
||||||
func (r *R) unlockedInjectFlow(from, to *nebula.Control, p *udp.Packet, tun bool) *packet {
|
func (r *R) unlockedInjectFlow(from, to *nebula.Control, p *udp.Packet, tun bool) *packet {
|
||||||
|
if r.flow == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
fp := &packet{
|
fp := &packet{
|
||||||
from: from,
|
from: from,
|
||||||
to: to,
|
to: to,
|
||||||
packet: p.Copy(),
|
packet: p.Copy(),
|
||||||
tun: tun,
|
tun: tun,
|
||||||
}
|
}
|
||||||
|
|
||||||
r.flow = append(r.flow, flowEntry{packet: fp})
|
r.flow = append(r.flow, flowEntry{packet: fp})
|
||||||
return fp
|
return fp
|
||||||
}
|
}
|
||||||
@@ -285,7 +316,7 @@ func (r *R) RouteUntilTxTun(sender *nebula.Control, receiver *nebula.Control) []
|
|||||||
}
|
}
|
||||||
fp := r.unlockedInjectFlow(sender, c, p, false)
|
fp := r.unlockedInjectFlow(sender, c, p, false)
|
||||||
c.InjectUDPPacket(p)
|
c.InjectUDPPacket(p)
|
||||||
fp.rx = true
|
fp.WasReceived()
|
||||||
r.Unlock()
|
r.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,7 +375,7 @@ func (r *R) RouteForAllUntilTxTun(receiver *nebula.Control) []byte {
|
|||||||
}
|
}
|
||||||
fp := r.unlockedInjectFlow(cm[x], c, p, false)
|
fp := r.unlockedInjectFlow(cm[x], c, p, false)
|
||||||
c.InjectUDPPacket(p)
|
c.InjectUDPPacket(p)
|
||||||
fp.rx = true
|
fp.WasReceived()
|
||||||
}
|
}
|
||||||
r.Unlock()
|
r.Unlock()
|
||||||
}
|
}
|
||||||
@@ -381,14 +412,14 @@ func (r *R) RouteExitFunc(sender *nebula.Control, whatDo ExitFunc) {
|
|||||||
case RouteAndExit:
|
case RouteAndExit:
|
||||||
fp := r.unlockedInjectFlow(sender, receiver, p, false)
|
fp := r.unlockedInjectFlow(sender, receiver, p, false)
|
||||||
receiver.InjectUDPPacket(p)
|
receiver.InjectUDPPacket(p)
|
||||||
fp.rx = true
|
fp.WasReceived()
|
||||||
r.Unlock()
|
r.Unlock()
|
||||||
return
|
return
|
||||||
|
|
||||||
case KeepRouting:
|
case KeepRouting:
|
||||||
fp := r.unlockedInjectFlow(sender, receiver, p, false)
|
fp := r.unlockedInjectFlow(sender, receiver, p, false)
|
||||||
receiver.InjectUDPPacket(p)
|
receiver.InjectUDPPacket(p)
|
||||||
fp.rx = true
|
fp.WasReceived()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unknown exitFunc return: %v", e))
|
panic(fmt.Sprintf("Unknown exitFunc return: %v", e))
|
||||||
@@ -439,7 +470,7 @@ func (r *R) InjectUDPPacket(sender, receiver *nebula.Control, packet *udp.Packet
|
|||||||
|
|
||||||
fp := r.unlockedInjectFlow(sender, receiver, packet, false)
|
fp := r.unlockedInjectFlow(sender, receiver, packet, false)
|
||||||
receiver.InjectUDPPacket(packet)
|
receiver.InjectUDPPacket(packet)
|
||||||
fp.rx = true
|
fp.WasReceived()
|
||||||
}
|
}
|
||||||
|
|
||||||
// RouteForUntilAfterToAddr will route for sender and return only after it sees and sends a packet destined for toAddr
|
// RouteForUntilAfterToAddr will route for sender and return only after it sees and sends a packet destined for toAddr
|
||||||
@@ -503,14 +534,14 @@ func (r *R) RouteForAllExitFunc(whatDo ExitFunc) {
|
|||||||
case RouteAndExit:
|
case RouteAndExit:
|
||||||
fp := r.unlockedInjectFlow(cm[x], receiver, p, false)
|
fp := r.unlockedInjectFlow(cm[x], receiver, p, false)
|
||||||
receiver.InjectUDPPacket(p)
|
receiver.InjectUDPPacket(p)
|
||||||
fp.rx = true
|
fp.WasReceived()
|
||||||
r.Unlock()
|
r.Unlock()
|
||||||
return
|
return
|
||||||
|
|
||||||
case KeepRouting:
|
case KeepRouting:
|
||||||
fp := r.unlockedInjectFlow(cm[x], receiver, p, false)
|
fp := r.unlockedInjectFlow(cm[x], receiver, p, false)
|
||||||
receiver.InjectUDPPacket(p)
|
receiver.InjectUDPPacket(p)
|
||||||
fp.rx = true
|
fp.WasReceived()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unknown exitFunc return: %v", e))
|
panic(fmt.Sprintf("Unknown exitFunc return: %v", e))
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ import (
|
|||||||
func (f *Interface) consumeInsidePacket(packet []byte, fwPacket *firewall.Packet, nb, out []byte, q int, localCache firewall.ConntrackCache) {
|
func (f *Interface) consumeInsidePacket(packet []byte, fwPacket *firewall.Packet, nb, out []byte, q int, localCache firewall.ConntrackCache) {
|
||||||
err := newPacket(packet, false, fwPacket)
|
err := newPacket(packet, false, fwPacket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if f.l.Level >= logrus.DebugLevel {
|
||||||
f.l.WithField("packet", packet).Debugf("Error while validating outbound packet: %s", err)
|
f.l.WithField("packet", packet).Debugf("Error while validating outbound packet: %s", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,8 +86,7 @@ func (f *Interface) Handshake(vpnIp iputil.VpnIp) {
|
|||||||
|
|
||||||
// getOrHandshake returns nil if the vpnIp is not routable
|
// getOrHandshake returns nil if the vpnIp is not routable
|
||||||
func (f *Interface) getOrHandshake(vpnIp iputil.VpnIp) *HostInfo {
|
func (f *Interface) getOrHandshake(vpnIp iputil.VpnIp) *HostInfo {
|
||||||
//TODO: we can find contains without converting back to bytes
|
if !ipMaskContains(f.lightHouse.myVpnIp, f.lightHouse.myVpnZeros, vpnIp) {
|
||||||
if f.hostMap.vpnCIDR.Contains(vpnIp.ToIP()) == false {
|
|
||||||
vpnIp = f.inside.RouteFor(vpnIp)
|
vpnIp = f.inside.RouteFor(vpnIp)
|
||||||
if vpnIp == 0 {
|
if vpnIp == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -327,7 +327,7 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg
|
|||||||
//TODO: check if we _should_ be emitting stats
|
//TODO: check if we _should_ be emitting stats
|
||||||
go ifce.emitStats(ctx, c.GetDuration("stats.interval", time.Second*10))
|
go ifce.emitStats(ctx, c.GetDuration("stats.interval", time.Second*10))
|
||||||
|
|
||||||
attachCommands(l, ssh, hostMap, handshakeManager.pendingHostMap, lightHouse, ifce)
|
attachCommands(l, c, ssh, hostMap, handshakeManager.pendingHostMap, lightHouse, ifce)
|
||||||
|
|
||||||
// Start DNS server last to allow using the nebula IP as lighthouse.dns.host
|
// Start DNS server last to allow using the nebula IP as lighthouse.dns.host
|
||||||
var dnsStart func()
|
var dnsStart func()
|
||||||
|
|||||||
10
outside.go
10
outside.go
@@ -34,6 +34,16 @@ func (f *Interface) readOutsidePackets(addr *udp.Addr, via interface{}, out []by
|
|||||||
}
|
}
|
||||||
|
|
||||||
//l.Error("in packet ", header, packet[HeaderLen:])
|
//l.Error("in packet ", header, packet[HeaderLen:])
|
||||||
|
if addr != nil {
|
||||||
|
if ip4 := addr.IP.To4(); ip4 != nil {
|
||||||
|
if ipMaskContains(f.lightHouse.myVpnIp, f.lightHouse.myVpnZeros, iputil.VpnIp(binary.BigEndian.Uint32(ip4))) {
|
||||||
|
if f.l.Level >= logrus.DebugLevel {
|
||||||
|
f.l.WithField("udpAddr", addr).Debug("Refusing to process double encrypted packet")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var hostinfo *HostInfo
|
var hostinfo *HostInfo
|
||||||
// verify if we've seen this index before, otherwise respond to the handshake initiation
|
// verify if we've seen this index before, otherwise respond to the handshake initiation
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/slackhq/nebula/cidr"
|
||||||
"github.com/slackhq/nebula/iputil"
|
"github.com/slackhq/nebula/iputil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,12 +18,14 @@ type tun struct {
|
|||||||
io.ReadWriteCloser
|
io.ReadWriteCloser
|
||||||
fd int
|
fd int
|
||||||
cidr *net.IPNet
|
cidr *net.IPNet
|
||||||
|
routeTree *cidr.Tree4
|
||||||
l *logrus.Logger
|
l *logrus.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTunFromFd(l *logrus.Logger, deviceFd int, cidr *net.IPNet, _ int, routes []Route, _ int) (*tun, error) {
|
func newTunFromFd(l *logrus.Logger, deviceFd int, cidr *net.IPNet, _ int, routes []Route, _ int) (*tun, error) {
|
||||||
if len(routes) > 0 {
|
routeTree, err := makeRouteTree(l, routes, false)
|
||||||
return nil, fmt.Errorf("routes are not supported in %s", runtime.GOOS)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
file := os.NewFile(uintptr(deviceFd), "/dev/net/tun")
|
file := os.NewFile(uintptr(deviceFd), "/dev/net/tun")
|
||||||
@@ -33,6 +35,7 @@ func newTunFromFd(l *logrus.Logger, deviceFd int, cidr *net.IPNet, _ int, routes
|
|||||||
fd: int(file.Fd()),
|
fd: int(file.Fd()),
|
||||||
cidr: cidr,
|
cidr: cidr,
|
||||||
l: l,
|
l: l,
|
||||||
|
routeTree: routeTree,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +43,12 @@ func newTun(_ *logrus.Logger, _ string, _ *net.IPNet, _ int, _ []Route, _ int, _
|
|||||||
return nil, fmt.Errorf("newTun not supported in Android")
|
return nil, fmt.Errorf("newTun not supported in Android")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tun) RouteFor(iputil.VpnIp) iputil.VpnIp {
|
func (t *tun) RouteFor(ip iputil.VpnIp) iputil.VpnIp {
|
||||||
|
r := t.routeTree.MostSpecificContains(ip)
|
||||||
|
if r != nil {
|
||||||
|
return r.(iputil.VpnIp)
|
||||||
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,32 +9,35 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/slackhq/nebula/cidr"
|
||||||
"github.com/slackhq/nebula/iputil"
|
"github.com/slackhq/nebula/iputil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tun struct {
|
type tun struct {
|
||||||
io.ReadWriteCloser
|
io.ReadWriteCloser
|
||||||
cidr *net.IPNet
|
cidr *net.IPNet
|
||||||
|
routeTree *cidr.Tree4
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTun(_ *logrus.Logger, _ string, _ *net.IPNet, _ int, _ []Route, _ int, _ bool) (*tun, error) {
|
func newTun(_ *logrus.Logger, _ string, _ *net.IPNet, _ int, _ []Route, _ int, _ bool) (*tun, error) {
|
||||||
return nil, fmt.Errorf("newTun not supported in iOS")
|
return nil, fmt.Errorf("newTun not supported in iOS")
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTunFromFd(_ *logrus.Logger, deviceFd int, cidr *net.IPNet, _ int, routes []Route, _ int) (*tun, error) {
|
func newTunFromFd(l *logrus.Logger, deviceFd int, cidr *net.IPNet, _ int, routes []Route, _ int) (*tun, error) {
|
||||||
if len(routes) > 0 {
|
routeTree, err := makeRouteTree(l, routes, false)
|
||||||
return nil, fmt.Errorf("routes are not supported in %s", runtime.GOOS)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
file := os.NewFile(uintptr(deviceFd), "/dev/tun")
|
file := os.NewFile(uintptr(deviceFd), "/dev/tun")
|
||||||
return &tun{
|
return &tun{
|
||||||
cidr: cidr,
|
cidr: cidr,
|
||||||
ReadWriteCloser: &tunReadCloser{f: file},
|
ReadWriteCloser: &tunReadCloser{f: file},
|
||||||
|
routeTree: routeTree,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +45,12 @@ func (t *tun) Activate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tun) RouteFor(iputil.VpnIp) iputil.VpnIp {
|
func (t *tun) RouteFor(ip iputil.VpnIp) iputil.VpnIp {
|
||||||
|
r := t.routeTree.MostSpecificContains(ip)
|
||||||
|
if r != nil {
|
||||||
|
return r.(iputil.VpnIp)
|
||||||
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/slackhq/nebula/cidr"
|
"github.com/slackhq/nebula/cidr"
|
||||||
@@ -49,7 +50,9 @@ func newTunFromFd(_ *logrus.Logger, _ int, _ *net.IPNet, _ int, _ []Route, _ int
|
|||||||
// These are unencrypted ip layer frames destined for another nebula node.
|
// These are unencrypted ip layer frames destined for another nebula node.
|
||||||
// packets should exit the udp side, capture them with udpConn.Get
|
// packets should exit the udp side, capture them with udpConn.Get
|
||||||
func (t *TestTun) Send(packet []byte) {
|
func (t *TestTun) Send(packet []byte) {
|
||||||
|
if t.l.Level >= logrus.InfoLevel {
|
||||||
t.l.WithField("dataLen", len(packet)).Info("Tun receiving injected packet")
|
t.l.WithField("dataLen", len(packet)).Info("Tun receiving injected packet")
|
||||||
|
}
|
||||||
t.rxPackets <- packet
|
t.rxPackets <- packet
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +110,10 @@ func (t *TestTun) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TestTun) Read(b []byte) (int, error) {
|
func (t *TestTun) Read(b []byte) (int, error) {
|
||||||
p := <-t.rxPackets
|
p, ok := <-t.rxPackets
|
||||||
|
if !ok {
|
||||||
|
return 0, os.ErrClosed
|
||||||
|
}
|
||||||
copy(b, p)
|
copy(b, p)
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|||||||
23
ssh.go
23
ssh.go
@@ -12,7 +12,6 @@ import (
|
|||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/slackhq/nebula/config"
|
"github.com/slackhq/nebula/config"
|
||||||
@@ -166,7 +165,7 @@ func configSSH(l *logrus.Logger, ssh *sshd.SSHServer, c *config.C) (func(), erro
|
|||||||
return runner, nil
|
return runner, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func attachCommands(l *logrus.Logger, ssh *sshd.SSHServer, hostMap *HostMap, pendingHostMap *HostMap, lightHouse *LightHouse, ifce *Interface) {
|
func attachCommands(l *logrus.Logger, c *config.C, ssh *sshd.SSHServer, hostMap *HostMap, pendingHostMap *HostMap, lightHouse *LightHouse, ifce *Interface) {
|
||||||
ssh.RegisterCommand(&sshd.Command{
|
ssh.RegisterCommand(&sshd.Command{
|
||||||
Name: "list-hostmap",
|
Name: "list-hostmap",
|
||||||
ShortDescription: "List all known previously connected hosts",
|
ShortDescription: "List all known previously connected hosts",
|
||||||
@@ -215,7 +214,9 @@ func attachCommands(l *logrus.Logger, ssh *sshd.SSHServer, hostMap *HostMap, pen
|
|||||||
ssh.RegisterCommand(&sshd.Command{
|
ssh.RegisterCommand(&sshd.Command{
|
||||||
Name: "reload",
|
Name: "reload",
|
||||||
ShortDescription: "Reloads configuration from disk, same as sending HUP to the process",
|
ShortDescription: "Reloads configuration from disk, same as sending HUP to the process",
|
||||||
Callback: sshReload,
|
Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
|
||||||
|
return sshReload(c, w)
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
ssh.RegisterCommand(&sshd.Command{
|
ssh.RegisterCommand(&sshd.Command{
|
||||||
@@ -875,16 +876,8 @@ func sshPrintTunnel(ifce *Interface, fs interface{}, a []string, w sshd.StringWr
|
|||||||
return enc.Encode(copyHostInfo(hostInfo, ifce.hostMap.preferredRanges))
|
return enc.Encode(copyHostInfo(hostInfo, ifce.hostMap.preferredRanges))
|
||||||
}
|
}
|
||||||
|
|
||||||
func sshReload(fs interface{}, a []string, w sshd.StringWriter) error {
|
func sshReload(c *config.C, w sshd.StringWriter) error {
|
||||||
p, err := os.FindProcess(os.Getpid())
|
err := w.WriteLine("Reloading config")
|
||||||
if err != nil {
|
c.ReloadConfig()
|
||||||
return w.WriteLine(err.Error())
|
return err
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
err = p.Signal(syscall.SIGHUP)
|
|
||||||
if err != nil {
|
|
||||||
return w.WriteLine(err.Error())
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
return w.WriteLine("HUP sent")
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,10 +62,12 @@ func (u *Conn) Send(packet *Packet) {
|
|||||||
if err := h.Parse(packet.Data); err != nil {
|
if err := h.Parse(packet.Data); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
if u.l.Level >= logrus.InfoLevel {
|
||||||
u.l.WithField("header", h).
|
u.l.WithField("header", h).
|
||||||
WithField("udpAddr", fmt.Sprintf("%v:%v", packet.FromIp, packet.FromPort)).
|
WithField("udpAddr", fmt.Sprintf("%v:%v", packet.FromIp, packet.FromPort)).
|
||||||
WithField("dataLen", len(packet.Data)).
|
WithField("dataLen", len(packet.Data)).
|
||||||
Info("UDP receiving injected packet")
|
Info("UDP receiving injected packet")
|
||||||
|
}
|
||||||
u.RxPackets <- packet
|
u.RxPackets <- packet
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +116,10 @@ func (u *Conn) ListenOut(r EncReader, lhf LightHouseHandlerFunc, cache *firewall
|
|||||||
nb := make([]byte, 12, 12)
|
nb := make([]byte, 12, 12)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
p := <-u.RxPackets
|
p, ok := <-u.RxPackets
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
ua.Port = p.FromPort
|
ua.Port = p.FromPort
|
||||||
copy(ua.IP, p.FromIp.To16())
|
copy(ua.IP, p.FromIp.To16())
|
||||||
r(ua, nil, plaintext[:0], p.Data, h, fwPacket, lhf, nb, q, cache.Get(u.l))
|
r(ua, nil, plaintext[:0], p.Data, h, fwPacket, lhf, nb, q, cache.Get(u.l))
|
||||||
|
|||||||
Reference in New Issue
Block a user