Skip to content

Commit

Permalink
basic example and start of readme
Browse files Browse the repository at this point in the history
  • Loading branch information
ik5 committed Feb 6, 2022
1 parent 19e4374 commit 71b9cc2
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 15 deletions.
27 changes: 27 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
gocapng
=======

The following code
-------------------

The following code provides a (C)Go binding for libcap-ng by Red-Hat using
__static__ linking.

The aim of the binding is to provide a Go'ish approach on using libcap-ng's API.
The code is only for Linux without a support for any additional OSes.

What is it all about
--------------------

The aim of POSIX's libcap and libcap-ng is to provide elevated permissions for
specific type of actions without becoming root, and only open it when required
and turn it off after performing the call itself.

In order to bind low port number (bellow 1024) you need to become root, or use
CAP_NET_BIND_SERVICE with libcap or libcap-ng.

The difference between libcap and libcap-ng is that libcap-ng is a library that
provides helps for taking care of POSIX libcap in simpler manner.



10 changes: 10 additions & 0 deletions examples/echo/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

output_name:=echo-server

build:
@rm "${output_name}" 2> /dev/null && echo "${output_name} cleaned" || true
@go build -o "${output_name}" *.go && echo "built ${output_name}"
sudo setcap CAP_NET_RAW,CAP_NET_BIND_SERVICE+ep "${output_name}"

clean:
@rm "${output_name}" 2> /dev/null && echo "${output_name} cleaned" || echo "nothing to clean"
Binary file added examples/echo/echo-server
Binary file not shown.
113 changes: 98 additions & 15 deletions examples/echo/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package main

import (
"errors"
"flag"
"fmt"
"io"
"net"
"os"
"os/signal"
Expand All @@ -11,7 +14,7 @@ import (
)

const (
echoPort = "7"
echoPort = 7
)

func handleSignals(quit chan bool) {
Expand All @@ -30,16 +33,34 @@ func handleSignals(quit chan bool) {
}
}

func echo() {
func echoTCP(conn net.Conn) {
buf := make([]byte, 4096)
for {
n, err := conn.Read(buf)
if errors.Is(err, io.EOF) {
break
}
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to read content: %s", err)
break
}
if n > 0 {
fmt.Fprintf(conn, "%s", buf[:n])
}
}

}

func listenServer(quit chan bool) {
func echoUDP(conn net.Conn) {

}

func listenTCPServer(quit chan bool) {
fmt.Println("Initializing Echo TCP Server")
tcpListen, err := net.Listen("tcp", ":"+echoPort)
tcpListen, err := net.Listen("tcp", fmt.Sprintf(":%d", echoPort))
if err != nil {
quit <- true
fmt.Fprintf(os.Stderr, "Unable to bind to on ':%s': %s", echoPort, err)
fmt.Fprintf(os.Stderr, "Unable to bind to on ':%d': %s", echoPort, err)
return
}
defer tcpListen.Close()
Expand All @@ -55,36 +76,98 @@ func listenServer(quit chan bool) {
continue
}

fmt.Fprintf(conn, "%s", conn)
go echoTCP(conn)
}
}
}

func listenUDPServer(quit chan bool) {
fmt.Println("Initializing Echo UDP Server")
conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: echoPort})
if err != nil {
quit <- true
fmt.Fprintf(os.Stderr, "Unable to bind to on ':%d': %s", echoPort, err)
return
}
defer conn.Close()

buf := make([]byte, 4096)
for {
select {
case <-quit:
return
default:
for {
n, addr, err := conn.ReadFromUDP(buf[:])
if errors.Is(err, io.EOF) {
break
}

if err != nil {
fmt.Fprintf(os.Stderr, "unable to read UDP: %s", err)
break
}

if n > 0 {
conn.WriteToUDP(buf[:n], addr)
}
}
}
}
}

func main() {
cap := gocapng.Init() // initialize libcap-ng
cap.Clear(gocapng.SelectAll) // clear memory, and set everything to "nothing"
listenUDP := flag.Bool("listen-udp", false, "Should the echo server listen to UDP")
flag.Parse()
cap := gocapng.Init() // initialize libcap-ng

if !cap.Updatev(
if !cap.GetCapsProcess() {
fmt.Println("Unable to get process capabilities")
os.Exit(1)
}

applyTo := gocapng.TypeInheritable
if !cap.Update(
gocapng.ActAdd,
gocapng.TypeEffective|gocapng.TypePermitted|gocapng.TypeBoundingSet,
applyTo,
gocapng.CAPSetPCap,
) {
fmt.Println("Unable to set CAPSetPCap")
os.Exit(1)
}

if !cap.Update(
gocapng.ActAdd,
applyTo,
gocapng.CAPSetFCap,
) {
fmt.Println("Unable to set CAPSetFCap")
os.Exit(1)
}

if !cap.Update(
gocapng.ActAdd,
applyTo,
gocapng.CAPNetBindService,
// gocapng.CAPSetFCap,
) {
fmt.Println("Unable to request capability for binding low port number.")
os.Exit(-1)
os.Exit(1)
}

err := cap.Apply(gocapng.SelectBoth)
err := cap.Apply(gocapng.SelectAmbient)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to apply capability: %s\n", err)
os.Exit(-2)
os.Exit(2)
}

quit := make(chan bool)
go handleSignals(quit)
go listenServer(quit)
if !*listenUDP {
go listenTCPServer(quit)
}
if *listenUDP {
go listenUDPServer(quit)
}

<-quit
}
Empty file added go.sum
Empty file.

0 comments on commit 71b9cc2

Please sign in to comment.