Skip to content

Instantly share code, notes, and snippets.

@xmdhs
Last active June 29, 2022 08:29
Show Gist options
  • Save xmdhs/062678d81502649931efa4833195a8d2 to your computer and use it in GitHub Desktop.
Save xmdhs/062678d81502649931efa4833195a8d2 to your computer and use it in GitHub Desktop.
minecraft lan list
package main
import (
"fmt"
"math/rand"
"net"
"os"
"strconv"
"sync"
"time"
)
func main() {
for i := 0; i < 100; i++ {
port := r.Intn(9999) + 1
go sendPing(randStr(10, []byte(atext)), strconv.Itoa(port))
}
os.Stdin.Read(make([]byte, 1))
}
type arand struct {
*rand.Rand
*sync.Mutex
}
var r = arand{
Rand: rand.New(rand.NewSource(time.Now().Unix())),
Mutex: &sync.Mutex{},
}
const atext = `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%`
func randStr(n int, words []byte) string {
b := make([]byte, n)
r.Lock()
for i := range b {
b[i] = words[r.Intn(len(words))]
}
r.Unlock()
return string(b)
}
func sendPing(motd, port string) {
dstAddr, err := net.ResolveUDPAddr("udp", "224.0.2.60:4445")
if err != nil {
panic(err)
}
srcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
conn, err := net.ListenUDP("udp", srcAddr)
if err != nil {
fmt.Println(err)
}
msg := []byte(fmt.Sprintf(`[MOTD]%s[/MOTD][AD]%s[/AD]`, motd, port))
for {
_, err := conn.WriteToUDP(msg, dstAddr)
if err != nil {
panic(err)
}
time.Sleep(2 * time.Second)
}
}
package main
import (
"context"
"errors"
"fmt"
"net"
"golang.org/x/net/ipv4"
)
func main() {
err := Listen(context.TODO(), "224.0.2.60:4445", "0.0.0.0", func(u *net.UDPAddr, b []byte) {
fmt.Println(string(b), u.String())
})
if err != nil {
panic(err)
}
}
const maxDatagramSize = 8024
func Listen(cxt context.Context, address, laddress string, handler func(*net.UDPAddr, []byte)) error {
msgCh := make(chan readMsg, 10)
errCh := make(chan error, 10)
addr, err := net.ResolveUDPAddr("udp4", address)
if err != nil {
return fmt.Errorf("Listen: %w", err)
}
il, err := net.Interfaces()
if err != nil {
return fmt.Errorf("Listen: %w", err)
}
if laddress != "0.0.0.0" {
lip := net.ParseIP(laddress)
var itf *net.Interface
B:
for _, v := range il {
addr, _ := v.Addrs()
for _, vv := range addr {
if ipnet, ok := vv.(*net.IPNet); ok && ipnet.IP.Equal(lip) {
itf = &v
break B
}
}
}
if itf == nil {
return fmt.Errorf("Listen: %w", ErrNotItf)
}
il = []net.Interface{*itf}
}
cxt, cancel := context.WithCancel(cxt)
defer cancel()
for _, v := range il {
if v.Flags&net.FlagMulticast != net.FlagMulticast || v.Flags&net.FlagUp != net.FlagUp {
continue
}
v := v
go read(cxt, &v, addr, errCh, msgCh)
}
for {
select {
case err := <-errCh:
return fmt.Errorf("Listen: %w", err)
case msg := <-msgCh:
handler(msg.addr, msg.msg)
case <-cxt.Done():
return nil
}
}
}
var ErrNotItf = errors.New("not find interface")
func read(cxt context.Context, itf *net.Interface, addr *net.UDPAddr, eCh chan<- error, msgCh chan<- readMsg) {
cxt, cancel := context.WithCancel(cxt)
defer cancel()
conn, err := net.ListenMulticastUDP("udp", itf, addr)
doErr := func(err error) {
select {
case <-cxt.Done():
case eCh <- fmt.Errorf("read: %w", err):
}
}
if err != nil {
doErr(err)
return
}
defer conn.Close()
go func() {
<-cxt.Done()
conn.Close()
}()
conn.SetReadBuffer(maxDatagramSize)
pc := ipv4.NewPacketConn(conn)
if err := pc.SetMulticastLoopback(true); err != nil {
doErr(err)
return
}
for {
buffer := make([]byte, maxDatagramSize)
numBytes, src, err := conn.ReadFromUDP(buffer)
if err != nil {
doErr(err)
return
}
select {
case msgCh <- readMsg{
addr: src,
msg: buffer[:numBytes],
}:
case <-cxt.Done():
return
}
}
}
type readMsg struct {
addr *net.UDPAddr
msg []byte
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment