Fast IP to CIDR lookup in Golang

Overview

cidranger

Fast IP to CIDR block(s) lookup using trie in Golang, inspired by IPv4 route lookup linux. Possible use cases include detecting if a IP address is from published cloud provider CIDR blocks (e.g. 52.95.110.1 is contained in published AWS Route53 CIDR 52.95.110.0/24), IP routing rules, etc.

GoDoc Reference Build Status Coverage Status Go Report Card

This is visualization of a trie storing CIDR blocks 128.0.0.0/2 192.0.0.0/2 200.0.0.0/5 without path compression, the 0/1 number on the path indicates the bit value of the IP address at specified bit position, hence the path from root node to a child node represents a CIDR block that contains all IP ranges of its children, and children's children.

Visualization of trie storing same CIDR blocks with path compression, improving both lookup speed and memory footprint.

Getting Started

Configure imports.

import (
  "net"

  "github.com/yl2chen/cidranger"
)

Create a new ranger implemented using Path-Compressed prefix trie.

ranger := NewPCTrieRanger()

Inserts CIDR blocks.

_, network1, _ := net.ParseCIDR("192.168.1.0/24")
_, network2, _ := net.ParseCIDR("128.168.1.0/24")
ranger.Insert(NewBasicRangerEntry(*network1))
ranger.Insert(NewBasicRangerEntry(*network2))

To attach any additional value(s) to the entry, simply create custom struct storing the desired value(s) that implements the RangerEntry interface:

type RangerEntry interface {
	Network() net.IPNet
}

The prefix trie can be visualized as:

0.0.0.0/0 (target_pos:31:has_entry:false)
| 1--> 128.0.0.0/1 (target_pos:30:has_entry:false)
| | 0--> 128.168.1.0/24 (target_pos:7:has_entry:true)
| | 1--> 192.168.1.0/24 (target_pos:7:has_entry:true)

To test if given IP is contained in constructed ranger,

contains, err = ranger.Contains(net.ParseIP("128.168.1.0")) // returns true, nil
contains, err = ranger.Contains(net.ParseIP("192.168.2.0")) // returns false, nil

To get all the networks given is contained in,

containingNetworks, err = ranger.ContainingNetworks(net.ParseIP("128.168.1.0"))

To get all networks in ranger,

entries, err := ranger.CoveredNetworks(*AllIPv4) // for IPv4
entries, err := ranger.CoveredNetworks(*AllIPv6) // for IPv6

Benchmark

Compare hit/miss case for IPv4/IPv6 using PC trie vs brute force implementation, Ranger is initialized with published AWS ip ranges (889 IPv4 CIDR blocks and 360 IPv6)

// Ipv4 lookup hit scenario
BenchmarkPCTrieHitIPv4UsingAWSRanges-4         	 5000000	       353   ns/op
BenchmarkBruteRangerHitIPv4UsingAWSRanges-4    	  100000	     13719   ns/op

// Ipv6 lookup hit scenario, counter-intuitively faster then IPv4 due to less IPv6 CIDR
// blocks in the AWS dataset, hence the constructed trie has less path splits and depth.
BenchmarkPCTrieHitIPv6UsingAWSRanges-4         	10000000	       143   ns/op
BenchmarkBruteRangerHitIPv6UsingAWSRanges-4    	  300000	      5178   ns/op

// Ipv4 lookup miss scenario
BenchmarkPCTrieMissIPv4UsingAWSRanges-4        	20000000	        96.5 ns/op
BenchmarkBruteRangerMissIPv4UsingAWSRanges-4   	   50000	     24781   ns/op

// Ipv6 lookup miss scenario
BenchmarkPCTrieHMissIPv6UsingAWSRanges-4       	10000000	       115   ns/op
BenchmarkBruteRangerMissIPv6UsingAWSRanges-4   	  100000	     10824   ns/op

Example of IPv6 trie:

::/0 (target_pos:127:has_entry:false)
| 0--> 2400::/14 (target_pos:113:has_entry:false)
| | 0--> 2400:6400::/22 (target_pos:105:has_entry:false)
| | | 0--> 2400:6500::/32 (target_pos:95:has_entry:false)
| | | | 0--> 2400:6500::/39 (target_pos:88:has_entry:false)
| | | | | 0--> 2400:6500:0:7000::/53 (target_pos:74:has_entry:false)
| | | | | | 0--> 2400:6500:0:7000::/54 (target_pos:73:has_entry:false)
| | | | | | | 0--> 2400:6500:0:7000::/55 (target_pos:72:has_entry:false)
| | | | | | | | 0--> 2400:6500:0:7000::/56 (target_pos:71:has_entry:true)
| | | | | | | | 1--> 2400:6500:0:7100::/56 (target_pos:71:has_entry:true)
| | | | | | | 1--> 2400:6500:0:7200::/56 (target_pos:71:has_entry:true)
| | | | | | 1--> 2400:6500:0:7400::/55 (target_pos:72:has_entry:false)
| | | | | | | 0--> 2400:6500:0:7400::/56 (target_pos:71:has_entry:true)
| | | | | | | 1--> 2400:6500:0:7500::/56 (target_pos:71:has_entry:true)
| | | | | 1--> 2400:6500:100:7000::/54 (target_pos:73:has_entry:false)
| | | | | | 0--> 2400:6500:100:7100::/56 (target_pos:71:has_entry:true)
| | | | | | 1--> 2400:6500:100:7200::/56 (target_pos:71:has_entry:true)
| | | | 1--> 2400:6500:ff00::/64 (target_pos:63:has_entry:true)
| | | 1--> 2400:6700:ff00::/64 (target_pos:63:has_entry:true)
| | 1--> 2403:b300:ff00::/64 (target_pos:63:has_entry:true)
Issues
  • bugfix:network:equality by ip&mask not string

    bugfix:network:equality by ip&mask not string

    Hello.

    Related Issues: #13

    The network compare ("82.253.252.7/14", "82.252.0.0/14") will cause the trie recursive call by the following code:

    package main
    
    import (
    	"math/rand"
    	"net"
    
    	"github.com/yl2chen/cidranger"
    )
    
    func main() {
    	trie := cidranger.NewPCTrieRanger()
    	rand.Seed(1)
    
    	addr := net.IP{
    		82, 253, 252, 7,
    	}
    
    	mask := net.IPMask{0xff, 0xff, 0xff, 0xfc}
    	err := trie.Insert(cidranger.NewBasicRangerEntry(net.IPNet{
    		IP:   addr,
    		Mask: mask,
    	}))
    	if err != nil {
    		panic(err)
    	}
    
    	mask = net.IPMask{0xff, 0xfc, 0x00, 0x00}
    	err = trie.Insert(cidranger.NewBasicRangerEntry(net.IPNet{
    		IP:   addr,
    		Mask: mask,
    	}))
    	if err != nil {
    		panic(err)
    	}
    }
    
    

    Signed-off-by: detailyang [email protected]

    opened by detailyang 5
  • performance improvement on certain operation

    performance improvement on certain operation

    include #37 but remove unnecessary changes, add the benchmark on this as well. before

    BenchmarkNetworkEqualIPv4-16          	 5917344	       198 ns/op	      64 B/op	       6 allocs/op
    BenchmarkNetworkEqualIPv6-16          	 4486786	       273 ns/op	      42 B/op	       6 allocs/op
    

    after

    BenchmarkNetworkEqualIPv4-16          	100000000	        10.6 ns/op	       0 B/op	       0 allocs/op
    BenchmarkNetworkEqualIPv6-16          	100000000	        10.9 ns/op	       0 B/op	       0 allocs/op
    

    change newPathprefixTrie to not call newPrefixTree, save time on extra parseCIDR and NewNetwork before

    BenchmarkNewPathprefixTriev4-16                                    	 2731194	       440 ns/op	     288 B/op	      12 allocs/op
    BenchmarkNewPathprefixTriev6-16                                    	 1610536	       743 ns/op	     456 B/op	      16 allocs/op
    

    after

    BenchmarkNewPathprefixTriev4-16                                    	13315774	        88.3 ns/op	      16 B/op	       4 allocs/op
    BenchmarkNewPathprefixTriev6-16                                    	 7967464	       153 ns/op	      64 B/op	       4 allocs/op
    
    opened by ldkingvivi 4
  • memory leak - removes do not get garbage collected

    memory leak - removes do not get garbage collected

    I'm noticing a behavior where deleted entries seem to not get reaped by garbage collection(runnable example below). For example if I add 1,000,000 entries and then Remove() them all and force a garbage collection, the ranger hangs onto the majority of the memory. If runs to 5 or so, you will see that it just grows and grows. Is this known? I took a look at the code but it's a bit hard for me to follow (as is most code I didn't write ;)

    Usage

    ./cidrtest -ips 1000000 -runs 5

    Sample Output

    STARTING RUN 0
    Starting Inserts
    1000000 Inserts Complete
    Observe Memory START Alloc = 615 MiB	TotalAlloc = 1828 MiB	Sys = 823 MiB	NumGC = 23
    Starting Removes
    ENDING RUN 0
    Observe Memory END Alloc = 546 MiB	TotalAlloc = 2688 MiB	Sys = 3624 MiB	NumGC = 26
    ...
    STARTING RUN 4
    Starting Inserts
    1000000 Inserts Complete
    Observe Memory START Alloc = 1164 MiB	TotalAlloc = 11699 MiB	Sys = 4585 MiB	NumGC = 39
    Starting Removes
    ENDING RUN 4
    Observe Memory END Alloc = 898 MiB	TotalAlloc = 12350 MiB	Sys = 4654 MiB	NumGC = 40
    

    Code

    package main
    
    import (
    	"encoding/binary"
    	"flag"
    	"fmt"
    	"math/rand"
    	"net"
    	"runtime"
    	"time"
    
    	"github.com/yl2chen/cidranger"
    )
    
    func main() {
    
    	ips := flag.Int("ips", 1000, "Number of IPs.  Default 1000")
    	runs := flag.Int("runs", 1000, "Number of runs.  Default 2")
    	flag.Parse()
    
    	mask := net.CIDRMask(32, 32)
    	trie := cidranger.NewPCTrieRanger()
    
    	// Main loop
    	for i := 0; i < *runs; i++ {
    		fmt.Printf("STARTING RUN %d\n", i)
    		fmt.Printf("Starting Inserts\n")
    		for n := 0; n < *ips; n++ {
    			trie.Insert(cidranger.NewBasicRangerEntry(net.IPNet{
    				IP:   GenIPV4(),
    				Mask: mask,
    			}))
    		}
    
    		fmt.Printf("%d Inserts Complete\n", *ips)
    		time.Sleep(5 * time.Second)
    		fmt.Printf("Observe Memory START ")
    		PrintMemUsage()
    		fmt.Printf("Starting Removes\n")
    		_, all, _ := net.ParseCIDR("0.0.0.0/0")
    		ll, _ := trie.CoveredNetworks(*all)
    		for i := 0; i < len(ll); i++ {
    			trie.Remove(ll[i].Network())
    		}
    		ll = nil
    		fmt.Printf("ENDING RUN %d\n", i)
    		fmt.Printf("Observe Memory END ")
    		runtime.GC()
    		PrintMemUsage()
    		time.Sleep(5 * time.Second)
    	}
    }
    
    // GenIPV4 generates an IPV4 address
    func GenIPV4() net.IP {
    	rand.Seed(time.Now().UnixNano())
    	var min, max int
    	min = 1
    	max = 4294967295
    	nn := rand.Intn(max-min) + min
    	ip := make(net.IP, 4)
    	binary.BigEndian.PutUint32(ip, uint32(nn))
    	return ip
    }
    
    // PrintMemUsage dumps memory stats for the process
    func PrintMemUsage() {
    	var m runtime.MemStats
    	runtime.ReadMemStats(&m)
    	fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc))
    	fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc))
    	fmt.Printf("\tSys = %v MiB", bToMb(m.Sys))
    	fmt.Printf("\tNumGC = %v\n", m.NumGC)
    }
    
    func bToMb(b uint64) uint64 {
    	return b / 1024 / 1024
    }
    
    opened by danmia 4
  • Releasing problem : v1.0.0 differs between Github and pkg.go.dev

    Releasing problem : v1.0.0 differs between Github and pkg.go.dev

    Thanks for the wonderful package, @yl2chen .

    Go's go mod tooling is pulling the wrong v1.0.0 of cidranger from : https://pkg.go.dev/github.com/yl2chen/[email protected]?tab=doc

    Notice the release date of 21-December-2019 above, and that cidranger.AllIPv4 and cidranger.AllIPv6 including the iterator implementation is missing from both sources and the documentation.

    This is in variance from the Github releases area, where v1.0.0 with date 24-December-2019, has all the above enhancements: https://github.com/yl2chen/cidranger/releases

    opened by s8mathur 3
  • sum.golang.org tag error

    sum.golang.org tag error

    Hello!

    I am getting an error trying to go get this code.

    sum.golang.org: SECURITY ERROR
    This download does NOT match the one reported by the checksum server.
    The bits may have been replaced on the origin server, or an attacker may\nhave intercepted the download attempt.
    
    For more information, see 'go help module-auth'.
    " http-method=GET http-path=/github.com/yl2chen/cidranger/@v/v1.0.0.info http-url=/github.com/yl2chen/cidranger/@v/v1.0.0.info kind="Internal Server Error" module=github.com/yl2chen/cidranger operation=download.InfoHandler ops="[download.InfoHandler pool.Info protocol.Info protocol.processDownload redis.Stash stash.Pool stasher.Stash stasher.fetchModule goGetFetcher.Fetch module.downloadModule]" version=v1.0.0
    

    Did you overwrite the 1.0.0 tag when you updated the coverage recently? I think bumping the tag to 1.0.1 might fix the problem.

    opened by jrmullins 3
  • Iterating over the cidrs

    Iterating over the cidrs

    Hi!

    Two questions:

    I created a ranger and inserted a few entries. Is there a way to iterate over the list of CIDR blocks?

    Also, is there something like ranger.Contains() that returns the data instead of a bool? I'm using something that implements the RangerEntry interface and I'd like to get back the entire thing.

    Thanks!

    opened by TomOnTime 3
  • Trying to insert next IP (/32 subnet) causes index out of range

    Trying to insert next IP (/32 subnet) causes index out of range

    Example code

    func main() {
    	ranger = cidranger.NewPCTrieRanger()
    	_, network1, _ := net.ParseCIDR("1.2.3.4/32")
    	ranger.Insert(cidranger.NewBasicRangerEntry(*network1))
    
    	_, network2, _ := net.ParseCIDR("1.2.3.5/32") // next IP
    	ranger.Insert(cidranger.NewBasicRangerEntry(*network2))
    }
    

    causes panic: runtime error: index out of range

    bug 
    opened by kkopachev 3
  • performance improvement on certain operation

    performance improvement on certain operation

    1. include https://github.com/yl2chen/cidranger/pull/37 but remove unnecessary changes, add the benchmark on this as well.

    before

    BenchmarkNetworkEqualIPv4-16          	 5917344	       198 ns/op	      64 B/op	       6 allocs/op
    BenchmarkNetworkEqualIPv6-16          	 4486786	       273 ns/op	      42 B/op	       6 allocs/op
    

    after

    BenchmarkNetworkEqualIPv4-16          	100000000	        10.6 ns/op	       0 B/op	       0 allocs/op
    BenchmarkNetworkEqualIPv6-16          	100000000	        10.9 ns/op	       0 B/op	       0 allocs/op
    
    1. change newPathprefixTrie to not call newPrefixTree, save time on extra parseCIDR and NewNetwork

    before

    BenchmarkNewPathprefixTriev4-16                                    	 2731194	       440 ns/op	     288 B/op	      12 allocs/op
    BenchmarkNewPathprefixTriev6-16                                    	 1610536	       743 ns/op	     456 B/op	      16 allocs/op
    

    after

    BenchmarkNewPathprefixTriev4-16                                    	13315774	        88.3 ns/op	      16 B/op	       4 allocs/op
    BenchmarkNewPathprefixTriev6-16                                    	 7967464	       153 ns/op	      64 B/op	       4 allocs/op
    
    opened by ldkingvivi 2
  • Duplicates are not maintained

    Duplicates are not maintained

    Hi,

    I love the library - thanks for sharing it.

    I initially assumed that if I inserted duplicate range entries, then both would be returned by ContainingNetworks(), but it appears that duplicates are eliminated. Looking at this code, I guess that's intentional? https://github.com/yl2chen/cidranger/blob/928b519e5268fe386d0f7decce320205cc09ca95/trie_test.go#L38-L41

    opened by aidansteele 2
  • out of memory error when adding many random ip nets

    out of memory error when adding many random ip nets

    Following code will produce an out of memory fatal error:

            trie := cidranger.NewPCTrieRanger()
            rand.Seed(1)
            addr := make([]byte, net.IPv4len)
            for n := 0; n < 1000; n += 1 {
                    rand.Read(addr)
                    cidr := int(rand.Uint32() % uint32(net.IPv4len*8))
                    mask := net.CIDRMask(cidr, net.IPv4len*8)
                    trie.Insert(cidranger.NewBasicRangerEntry(net.IPNet{
                            IP:   addr,
                            Mask: mask,
                    }))
            }
    

    Log shows that it's likely due to too many (*prefixTrie).insert recursive calls.

    opened by wxdao 2
  • Fixes errors produced by dep 0.5.0

    Fixes errors produced by dep 0.5.0

    Recent version of dep - 0.5.0 produces errors on dep status:

    ◦ dep status
    Gopkg.lock is out of sync with imports and/or Gopkg.toml. Run `dep check` for details.
    PROJECT  MISSING PACKAGES
    input-digest mismatch
    

    This commit updates Gopkg.lock to recent dep format

    I essentially ran dep ensure.

    opened by maciej 2
  • Custom Ranger Insert/Remove Hooks

    Custom Ranger Insert/Remove Hooks

    Having the ability to supply custom insertion/removal function hooks would be really useful if the data being added was a complex object like a map/slice/struct where specific merge behavior could be specified. This is primarily for the use case where I'm inserting multiple times for the same network with different data as this prevents the need to buffer and merge before inserting into the trie.

    opened by jhg03a 1
  • trie.go:insert - fix proposal for Ipv4\Ipv6 in same trie

    trie.go:insert - fix proposal for Ipv4\Ipv6 in same trie

    func (p *prefixTrie) insert(network rnet.Network, entry RangerEntry) (bool, error) {
            
                *                *                   *
    
    	// No existing child, insert new leaf trie.
    	if existingChild == nil || existingChild.network.Number == nil {
    
              *                   *                   *
    
    	}
    
              *                  *                  *
    
    	// Check whether it is necessary to insert additional path prefix between current trie and existing child,
    	// in the case that inserted network diverges on its path to existing child.
    	if lcb, err := network.LeastCommonBitPosition(existingChild.network); err == nil {
    
              *                   *                  *
    
    	} else {
    		return false, err
    	}
    
    	return existingChild.insert(network, entry)
    }
    
    opened by dmineev 0
  • Custom RangerEntry with Overlapping Networks

    Custom RangerEntry with Overlapping Networks

    As posted below, you indicate that there is a way to handle overlapping CIDRs with a custom RangerEntry type. However, it doesn't seem to be possible from what I can tell.

    We have a use case where we have multiple subnets that overlap, but are in different VRFs. We want to be able to load all these networks, enriched with the VRF in a custom RangerEntry type, and then retreive this data based on the VRF information.

    Please review the code here to see if there is a way to do what we are looking for. - https://play.golang.org/p/9_1PKzEixkr Thanks!


    Yes, deduplication were intentional, the idea behind it is that this will any metadata that you would like to attach to a CIDR block could be done through implementing your own custom type that implements the RangerEntry interface https://github.com/yl2chen/cidranger/blob/928b519e5268fe386d0f7decce320205cc09ca95/cidranger.go#L48

    Does that fit your use case?

    Originally posted by @yl2chen in https://github.com/yl2chen/cidranger/issues/14#issuecomment-487434204

    opened by tagur87 8
  • Key-value database with search by cidr

    Key-value database with search by cidr

    Hi Yulin Chen!

    Do you have any ideas how to create some key-value database where key is a cidr or some algorithm to fast find occurrence of an address in network?

    For example: You have a lot of network with various masks and some data about this networks. You try to find in which network this address exist and return data. I don't want iterate over in a loop all key-cidr and try to find solution with your cidrranger decision

    opened by MonaxGT 0
  • Convert IPv4 mapped IPv6 subnet masks to 4 bytes from 16 bytes (using the last 4 bytes)

    Convert IPv4 mapped IPv6 subnet masks to 4 bytes from 16 bytes (using the last 4 bytes)

    @yl2chen Currently, you can't add IPv4 mapped IPv6 networks.

    For example, If you try insert ::ffff:d1ad:35a7/128, a nil network will be inserted. This uses ipV4Ranger (as it is stored as IPv4 address internally), but the mask isn't converted and remains 16 bytes. Hence you have something like this 209.173.53.167/128 instead of 209.173.53.167/32.

    func (n Network) Masked(ones int) Network { mask := net.CIDRMask(ones, len(n.Number)*BitsPerUint32) return NewNetwork(net.IPNet{ IP: n.IP.Mask(mask), Mask: mask, }) }

    opened by damilola-bello 1
Owner
Yulin Chen
Yulin Chen
Go package provides a fast lookup of country, region, city, latitude, longitude, ZIP code, time zone, ISP, domain name,

IP2Location Go Package This Go package provides a fast lookup of country, region, city, latitude, longitude, ZIP code, time zone, ISP, domain name, co

IP2Location 273 Aug 12, 2022
DNS lookup service with golang

dns-lookup-service Dev Setup git clone https://github.com/philip1986/dns-lookup-service.git cd dns-lookup-service docker-compose up --build Load the

null 1 Feb 9, 2022
Jswhois - Whois lookup results in json format

jswhois -- whois lookup results in json format jswhois(1) is a tool to look up a

Jan Schaumann 39 Jul 11, 2022
llb - It's a very simple but quick backend for proxy servers. Can be useful for fast redirection to predefined domain with zero memory allocation and fast response.

llb What the f--k it is? It's a very simple but quick backend for proxy servers. You can setup redirect to your main domain or just show HTTP/1.1 404

Kirill Danshin 12 Jan 23, 2022
Simple, fast and scalable golang rpc library for high load

gorpc Simple, fast and scalable golang RPC library for high load and microservices. Gorpc provides the following features useful for highly loaded pro

Aliaksandr Valialkin 652 Jul 24, 2022
Snugger is a light weight but fast network recon scanner that is written from pure golang

Snugger is a light weight but fast network recon scanner that is written from pure golang. with this scann you can ARP your network, port scan hosts and host lists, as well as scan for BSSId

RE43P3R 2 May 19, 2022
Dofind - Dofind is fast domain related finder made with golang

Dofind is fast domain related finder made with golang. ██████╗░░█████╗░███████╗

Muhamad Burhanudin 4 Feb 16, 2022
Chisel is a fast TCP/UDP tunnel, transported over HTTP, secured via SSH.

Chisel is a fast TCP/UDP tunnel, transported over HTTP, secured via SSH. Single executable including both client and server. Written in Go (golang). Chisel is mainly useful for passing through firewalls, though it can also be used to provide a secure endpoint into your network.

Jaime Pillora 7.6k Aug 8, 2022
Fast HTTP package for Go. Tuned for high performance. Zero memory allocations in hot paths. Up to 10x faster than net/http

fasthttp Fast HTTP implementation for Go. Currently fasthttp is successfully used by VertaMedia in a production serving up to 200K rps from more than

Aliaksandr Valialkin 18.2k Aug 15, 2022
🚀Gev is a lightweight, fast non-blocking TCP network library based on Reactor mode. Support custom protocols to quickly and easily build high-performance servers.

gev 中文 | English gev is a lightweight, fast non-blocking TCP network library based on Reactor mode. Support custom protocols to quickly and easily bui

徐旭 1.5k Aug 8, 2022
Fast RFC 5389 STUN implementation in go

STUN Package stun implements Session Traversal Utilities for NAT (STUN) [RFC5389] protocol and client with no external dependencies and zero allocatio

null 488 Aug 15, 2022
A MCBE Proxy supporting fast transfer and much more!

Downloads Pipelines Here you can find all the build please select the latest and click Artifacts

sun_proxy 29 Jul 22, 2022
An incredibly fast proxy checker & IP rotator with ease.

An incredibly fast proxy checker & IP rotator with ease.

Kitabisa 753 Aug 7, 2022
A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.

frp README | 中文文档 What is frp? frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the Internet. As of now, it s

null 58.8k Aug 9, 2022
Fast, multithreaded, modular and extensible DHCP server written in Go

coredhcp Fast, multithreaded, modular and extensible DHCP server written in Go This is still a work-in-progress Example configuration In CoreDHCP almo

CoreDHCP 760 Aug 16, 2022
Fast RFC 5389 STUN implementation in go

STUN Package stun implements Session Traversal Utilities for NAT (STUN) [RFC5389] protocol and client with no external dependencies and zero allocatio

null 488 Aug 15, 2022
A modern, fast and scalable websocket framework with elegant API written in Go

About neffos Neffos is a cross-platform real-time framework with expressive, elegant API written in Go. Neffos takes the pain out of development by ea

Gerasimos (Makis) Maropoulos 393 Jul 29, 2022
Fast and idiomatic client-driven REST APIs.

Vulcain is a brand new protocol using HTTP/2 Server Push to create fast and idiomatic client-driven REST APIs. An open source gateway server which you

Kévin Dunglas 3.3k Aug 10, 2022
Fast event-loop networking for Go

evio is an event loop networking framework that is fast and small. It makes direct epoll and kqueue syscalls rather than using the standard Go net pac

Josh 5.4k Aug 15, 2022