Skip to content
Snippets Groups Projects
Commit d82d0d15 authored by Volker Schukai's avatar Volker Schukai :alien:
Browse files

first version of the code

parent aa8834e3
No related branches found
No related tags found
No related merge requests found
/coverage/
/bin/
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
\ No newline at end of file
image: golang:1.16-buster
cache:
paths:
- /apt-cache
- /go/src/github.com
- /go/src/golang.org
- /go/src/google.golang.org
- /go/src/gopkg.in
stages:
- test
before_script:
unit_tests:
stage: test
script:
- make test
only:
- merge_requests
race_detector:
stage: test
script:
- make test-race
only:
- merge_requests
code_coverage:
stage: test
script:
- make coverage
only:
- merge_requests
lint_code:
stage: test
script:
- make lint
only:
- merge_requests
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="accountSettings">
<option name="activeProfile" value="profile:default" />
<option name="activeRegion" value="eu-west-1" />
<option name="recentlyUsedProfiles">
<list>
<option value="profile:default" />
</list>
</option>
<option name="recentlyUsedRegions">
<list>
<option value="eu-west-1" />
</list>
</option>
</component>
</project>
\ No newline at end of file
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MarkdownEnhProjectSettings">
<AnnotatorSettings targetHasSpaces="true" linkCaseMismatch="true" wikiCaseMismatch="true" wikiLinkHasDashes="true" notUnderWikiHome="true" targetNotWikiPageExt="true" notUnderSourceWikiHome="true" targetNameHasAnchor="true" targetPathHasAnchor="true" wikiLinkHasSlash="true" wikiLinkHasSubdir="true" wikiLinkHasOnlyAnchor="true" linkTargetsWikiHasExt="true" linkTargetsWikiHasBadExt="true" notUnderSameRepo="true" targetNotUnderVcs="false" linkNeedsExt="true" linkHasBadExt="true" linkTargetNeedsExt="true" linkTargetHasBadExt="true" wikiLinkNotInWiki="true" imageTargetNotInRaw="true" repoRelativeAcrossVcsRoots="true" multipleWikiTargetsMatch="true" unresolvedLinkReference="true" linkIsIgnored="true" anchorIsIgnored="true" anchorIsUnresolved="true" anchorLineReferenceIsUnresolved="true" anchorLineReferenceFormat="true" anchorHasDuplicates="true" abbreviationDuplicates="true" abbreviationNotUsed="true" attributeIdDuplicateDefinition="true" attributeIdNotUsed="true" footnoteDuplicateDefinition="true" footnoteUnresolved="true" footnoteDuplicates="true" footnoteNotUsed="true" macroDuplicateDefinition="true" macroUnresolved="true" macroDuplicates="true" macroNotUsed="true" referenceDuplicateDefinition="true" referenceUnresolved="true" referenceDuplicates="true" referenceNotUsed="true" referenceUnresolvedNumericId="true" enumRefDuplicateDefinition="true" enumRefUnresolved="true" enumRefDuplicates="true" enumRefNotUsed="true" enumRefLinkUnresolved="true" enumRefLinkDuplicates="true" simTocUpdateNeeded="true" simTocTitleSpaceNeeded="true" />
<HtmlExportSettings updateOnSave="false" parentDir="" targetDir="" cssDir="css" scriptDir="js" plainHtml="false" imageDir="" copyLinkedImages="false" imagePathType="0" targetPathType="2" targetExt="" useTargetExt="false" noCssNoScripts="false" useElementStyleAttribute="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" linkFormatType="HTTP_ABSOLUTE" />
<LinkMapSettings>
<textMaps />
</LinkMapSettings>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MarkdownProjectSettings">
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" synchronizePreviewPosition="true" highlightPreviewType="LINE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="true" showSelectionInPreview="true" lastLayoutSetsDefault="false">
<PanelProvider>
<provider providerId="com.vladsch.md.nav.editor.swing.html.panel" providerName="Default - Swing" />
</PanelProvider>
</PreviewSettings>
<ParserSettings gitHubSyntaxChange="false" correctedInvalidSettings="false" emojiShortcuts="1" emojiImages="0">
<PegdownExtensions>
<option name="ATXHEADERSPACE" value="true" />
<option name="FENCED_CODE_BLOCKS" value="true" />
<option name="INTELLIJ_DUMMY_IDENTIFIER" value="true" />
<option name="RELAXEDHRULES" value="true" />
<option name="STRIKETHROUGH" value="true" />
<option name="TABLES" value="true" />
<option name="TASKLISTITEMS" value="true" />
</PegdownExtensions>
<ParserOptions>
<option name="COMMONMARK_LISTS" value="true" />
<option name="EMOJI_SHORTCUTS" value="true" />
<option name="GFM_TABLE_RENDERING" value="true" />
<option name="PRODUCTION_SPEC_PARSER" value="true" />
<option name="SIM_TOC_BLANK_LINE_SPACER" value="true" />
</ParserOptions>
</ParserSettings>
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" addPageHeader="false" addAnchorLinks="false" anchorLinksWrapText="false" imageUriSerials="false" addDocTypeHtml="true" noParaTags="false" defaultUrlTitle="false" migratedPlantUml="true" migratedAnchorLinks="true" plantUmlConversion="0">
<GeneratorProvider>
<provider providerId="com.vladsch.md.nav.editor.text.html.generator" providerName="Unmodified HTML Generator" />
</GeneratorProvider>
<headerTop />
<headerBottom />
<bodyTop />
<bodyBottom />
<fencedCodeConversions>
<option name="c4plantuml" value="NONE" />
<option name="ditaa" value="NONE" />
<option name="erd" value="NONE" />
<option name="graphviz" value="NONE" />
<option name="latex" value="KATEX" />
<option name="math" value="KATEX" />
<option name="mermaid" value="NONE" />
<option name="nomnoml" value="NONE" />
<option name="plantuml" value="NONE" />
<option name="puml" value="NONE" />
<option name="svgbob" value="NONE" />
<option name="umlet" value="NONE" />
<option name="vega" value="NONE" />
<option name="vegalite" value="NONE" />
<option name="wavedrom" value="NONE" />
</fencedCodeConversions>
</HtmlSettings>
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssUriSerial="true" isCssTextEnabled="false" isDynamicPageWidth="true">
<StylesheetProvider>
<provider providerId="com.vladsch.md.nav.editor.text.html.css" providerName="No Stylesheet" />
</StylesheetProvider>
<ScriptProviders />
<cssText />
<cssUriHistory />
</CssSettings>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/traceroute.iml" filepath="$PROJECT_DIR$/traceroute.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
\ No newline at end of file
Makefile 0 → 100644
#PACKAGES ?= $(shell basename `go list`)
#FILES ?= $(shell find . -type f -name '*.go' -not -path "./vendor/*")
#VERSION ?= $(shell git describe --tags --always --dirty --match=v* 2> /dev/null || cat $(PWD)/.version 2> /dev/null || echo v0)
##PACKAGE ?= $(shell go list)
##PACKAGES ?= $(shell go list ./...)
PROJECT_NAME := "traceroute"
PKG := "gitlab.schukai.com/oss/libraries/go/network/traceroute"
PKG_LIST := $(shell go list ${PKG}/... )
GO_FILES := $(shell find . -name '*.go')
#GO_FILES := $(shell find . -name '*.go' | grep -v _test.go)
GOCMD=go
GOBUILD=$(GOCMD) build
GOCLEAN=$(GOCMD) clean
GOTEST=$(GOCMD) test
GOVET=$(GOCMD) vet
GOGET=$(GOCMD) get
GOFMT=$(GOCMD) fmt
GODOC=$(GOCMD) fmt
GOLINT=golint
default: help
help: ## show this help
@echo 'usage: make [target] ...'
@echo ''
@echo 'targets:'
@egrep '^(.+)\:\ .*##\ (.+)' ${MAKEFILE_LIST} | sed 's/:.*##/#/' | column -t -c 2 -s '#'
clean: ## go clean
$(GOCLEAN)
clean-all: ## remove all generated artifacts and clean all build artifacts
$(GOCLEAN) -i ./...
lint: ## run go lint on the source files
$(GOLINT) -set_exit_status .
vet: ## run go vet on the source files
$(GOVET) ./...
doc: ## generate godocs and start a local documentation webserver on port 8085
godoc -http=:8085 -index
test: ## test package
$(GOTEST) -v $(PKG_LIST)
test-race: ## run race-tests
$(GOTEST) -race $(PKG_LIST)
benchmark: ## run benchmark tests
$(GOTEST) -bench .
coverage: coverage/cover.html ## Run test coverage and generate html report
coverage/cover.html: $(GO_FILES)
mkdir -p coverage
$(GOCMD) list -f '{{if gt (len .TestGoFiles) 0}}"go test -covermode count -coverprofile {{.Name}}.coverprofile -coverpkg ./... {{.ImportPath}}"{{end}}' ./... | xargs -I {} bash -c {}
echo "mode: count" > coverage/cover.out
grep -h -v "^mode:" *.coverprofile >> "coverage/cover.out"
rm *.coverprofile
$(GOCMD) tool cover -html=coverage/cover.out -o=coverage/cover.html
test-all: test test-race benchmark coverage
fmt: ## format the go source files
$(GOFMT) .
all: ## clean, format and unit test
make clean-all
make fmt
make test-all
build-cmd:
mkdir -p bin
$(GOCMD) build -o bin/traceroute cmd/main.go
sudo setcap cap_net_raw+ep bin/traceroute
# traceroute # Traceroute
This library allows to record a traceroute.
## Requirements
To execute the traceroute, a privileged port must be opened. this
requires special permissions. One possibility is .
A prerequisite for reading incoming traffic is being able to either to
be root or set the executable capability `CAP_NET_RAW`.
Reminder: You can set the `CAP_NET_RAW` capability on an executable like
this:
```bash
sudo setcap cap_net_raw+ep /path/to/executable
```
Look at manpage for [setcap](https://linux.die.net/man/8/setcap)
You can also change the restrictions on unprivileged ports.
```bash
sudo /sbin/sysctl -w net.ipv4.ip_unprivileged_port_start=0
```
for the purpose of debugging, pkttyagent can also be taken.
```bash
# PID is the processid
pkttyagent --process PID-OF-IDE
## für netbeans
pkttyagent --process $(ps -xa | grep "netbeans" )
## für intellij
pkttyagent --process $(ps -xa | grep "IntelliJ-IDEA-Ultimate/jbr/bin/java" )
```
## Installation
The recommended way to install this package is
```bash
go get gitlab.schukai.com/oss/libraries/go/network/traceroute
```
## Usage
First, a session must be created `traceroute.NewSession(host)`. Then the
traceroute can be executed `session.TraceRoute()`.
Either waits for the result and continues working with it, or
Specifies a callback that is called directly after a hop.
```go
package main
import (
"flag"
"fmt"
"gitlab.schukai.com/oss/libraries/go/network/traceroute"
)
const (
flagValue = ""
flagUsage = "hostname or ip address"
)
func main() {
var host string
flag.StringVar(&host, "h", flagValue, flagUsage+" (shorthand)")
flag.StringVar(&host, "host", flagValue, flagUsage)
flag.Parse()
if host == "" {
fmt.Println("missing host")
flag.Usage()
return
}
session, err := traceroute.NewSession(host)
if err != nil {
flag.Usage()
return
}
session.CallBack = func(result traceroute.Result) {
if result.Err!=nil {
fmt.Printf("%v\t%s\t\t\t\t%v\t\t(%s)\n", result.Hop, result.Station, result.Latency, result.Err.Error())
return
}
fmt.Printf("%v\t%s\t\t\t%v\n", result.Hop, result.Station, result.Latency)
}
_, err=session.TraceRoute()
if err!=nil {
fmt.Println(err.Error())
}
}
```
File added
package main
import (
"flag"
"fmt"
"gitlab.schukai.com/oss/libraries/go/network/traceroute"
)
const (
flagValue = ""
flagUsage = "hostname or ip address"
)
func main() {
var host string
flag.StringVar(&host, "h", flagValue, flagUsage+" (shorthand)")
flag.StringVar(&host, "host", flagValue, flagUsage)
flag.Parse()
if host == "" {
fmt.Println("missing host")
flag.Usage()
return
}
session, err := traceroute.NewSession(host)
if err != nil {
flag.Usage()
return
}
session.CallBack = func(result traceroute.Result) {
if result.Err!=nil {
fmt.Printf("%v\t%s\t\t\t\t%v\t\t(%s)\n", result.Hop, result.Station, result.Latency, result.Err.Error())
return
}
fmt.Printf("%v\t%s\t\t\t%v\n", result.Hop, result.Station, result.Latency)
}
_, err=session.TraceRoute()
if err!=nil {
fmt.Println(err.Error())
}
}
dns.go 0 → 100644
package traceroute
import (
"errors"
"net"
)
func resolveDNS(hostname string) (*address, error) {
ips, err := net.LookupIP(hostname)
if err != nil {
return nil, err
}
var ipV4 net.IP
for _, ip := range ips {
if len(ip) == net.IPv6len {
return &address{ip: ip, version: addressV6}, nil
} else if len(ip) == net.IPv4len {
ipV4 = ip
}
}
if ipV4 != nil {
return &address{ip: ipV4, version: addressV4}, nil
}
return nil, errors.New("could not find a valid record for " + hostname)
}
// DNS resolution utility function (IPv6/IPv4)
func resolve(hostname string) (*address, error) {
ip := net.ParseIP(hostname)
if ip.To4() != nil {
return &address{ip: ip, version: addressV4}, nil
}
if ip.To16() != nil {
return &address{ip: ip, version: addressV6}, nil
}
return resolveDNS(hostname)
}
package traceroute
import (
"fmt"
"testing"
)
func TestResolve(t *testing.T) {
testCases := []struct {
name string
should string
shouldHasError bool
shouldVersion int
}{
{"schukai.com", "80.147.206.177", false, addressV4},
{"unsupported", "", true, addressV4},
{"::ffff:192.0.2.1", "192.0.2.1", false, addressV4}, // ipv6 masked ipv4
{"127.0.0.1", "127.0.0.1", false, addressV4},
{"2001:4860:4860::8888", "2001:4860:4860::8888", false, addressV6},
{"example.com", "2606:2800:220:1:248:1893:25c8:1946", false, addressV6},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s should fail %t", tc.name, tc.shouldHasError), func(t *testing.T) {
address, err := resolve(tc.name)
if err != nil {
if tc.shouldHasError == true {
return
}
t.Errorf("dns query error: %s", err.Error())
}
if address.String() != tc.should {
t.Errorf("query %s should %s and not %s", tc.name, tc.should, address.String())
}
if tc.shouldVersion == addressV6 {
if address.isV6() != true || address.isV4() != false {
t.Errorf("query %s should version V6", tc.name)
}
} else {
if address.isV6() == true || address.isV4() == false {
t.Errorf("query %s should version V4", tc.name)
}
}
})
}
}
func benchmarkResolve(address string, b *testing.B) {
for n := 0; n < b.N; n++ {
resolve(address)
}
}
func BenchmarkResolve1(b *testing.B) { benchmarkResolve("www.google.com", b) }
func BenchmarkResolve2(b *testing.B) { benchmarkResolve("www.schukai.com", b) }
func BenchmarkResolve3(b *testing.B) { benchmarkResolve("2001:4860:4860::8888", b) }
func BenchmarkResolve4(b *testing.B) { benchmarkResolve("unsupported", b) }
func BenchmarkResolve5(b *testing.B) { benchmarkResolve("127.0.0.1", b) }
go.mod 0 → 100644
ip.go 0 → 100644
package traceroute
import "net"
const (
unknown = 0
addressV4 = 4
addressV6 = 6
)
func isV4(ip net.IP) bool {
i := ip.To4()
if i != nil {
return true
}
return false
}
type address struct {
ip net.IP
version int
}
func (a address) isV4() bool {
return a.version == addressV4
}
func (a address) isV6() bool {
return a.version == addressV6
}
func (a address) isUnknow() bool {
return a.version == unknown
}
func (a address) String() string {
return a.ip.String()
}
func (a address) Network() string {
r:= net.IPAddr{
IP: a.ip,
Zone: "",
}
return r.Network()
}
func newAddress(ip net.IP) address {
if ip == nil {
return address{
ip: nil,
version: unknown,
}
}
if isV4(ip) {
return address{
ip: ip,
version: addressV4,
}
}
return address{
ip: ip,
version: addressV6,
}
}
package traceroute
import (
"fmt"
"net"
"testing"
)
func TestNewAddress(t *testing.T) {
testCases := []struct {
name string
mode int
}{
{"127.0.0.1",addressV4},
{"unsupported", unknown},
{"::ffff:192.0.2.1", addressV4},
{"2001:4860:4860::8888", addressV6},
{"2606:2800:220:1:248:1893:25c8:1946", addressV6},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s should fail %d", tc.name, tc.mode), func(t *testing.T) {
a:= newAddress(net.ParseIP(tc.name))
if a.isV4()&&tc.mode!=addressV4 {
t.Errorf("an error has occurred")
} else if a.isV6()&&tc.mode!=addressV6 {
t.Errorf("an error has occurred")
} else if a.isUnknow() &&tc.mode!=unknown{
t.Errorf("an error has occurred")
}
})
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment