diff --git a/README.md b/README.md index 16248d851d1656fde79657dbac889ba49cec7ed2..8cf502edd49cce5d85b25ea3911eccd17ef8226c 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,42 @@ Source Specific Multicast (SSM) custom sender and receiver, used to join and lea ## Receiver -go run ssm.go 193.17.9.3%232.223.222.1:4099 -i tun3 +go run ssmc.go 10.10.250.2%232.2.3.2:4099 -i tun3 + +The first packet will be displayed with it's index number for example: + +`S: 18939904` + +Each packet received thereafter will be represented by one of the following characters: + + ! : Packet with the correct next index sequence. + < : Packet index is less than the previous index. + > : Packet index is greater than the previous index. + +When the size of the packet changes this will be represented by "PS[new size]". + +Should the index ever be less than zero the end of stream will be reported with `EOS` followed by the last index. + +Example: + +``` +neteam@amt4:~/go/src/ssm$ go run receiver/ssmc.go 10.10.250.2%232.2.3.2:4099 -i ens4 +Server listening on UDP port 4099 +Joining multicast (S,G)=10.10.250.2,232.2.3.2 w/iface ens4 +S: 48PS[1470]!!!!!!!!!!!!!!!!!!!!!![4pps]!!!!!!!!!!!!EOS [i:-82] +``` ## Sender -go run ssmd.go 232.223.222.1:4099 +go run ssmd.go 10.10.250.2%232.2.3.2:4099 + +Each packet sent will be represented by ! + +When the sent packet size changes this will be represented by "PS[new size]". + +Example: + +``` +neteam@amt1:~/go/src/ssm$ go run sender/ssmd.go 10.10.250.2%232.2.3.2:4711 +!PS[64]!!!!!!PS[66]!PS[115]!PS[126]!PS[92]!PS[66]!PS[64]!!!!!!PS[66]!PS[115] +``` diff --git a/receiver/ssmc.go b/receiver/ssmc.go new file mode 100644 index 0000000000000000000000000000000000000000..f8c4a60b4fe46c907c34a0b2e9e7e66928a8b39d --- /dev/null +++ b/receiver/ssmc.go @@ -0,0 +1,160 @@ +package main + +import ( + //"encoding/binary" + "encoding/binary" + "fmt" + "net" + "os" + + //"runtime" + "regexp" + "time" + + "golang.org/x/net/ipv4" +) + +func usage() { + fmt.Println("USAGE: ssm <source>%<group>:<port>") + os.Exit(0) +} + +func main() { + arguments := os.Args + if len(arguments) < 2 { + usage() + } + + /* Process the SSM group join argument */ + + ssmarg := arguments[1] + re := regexp.MustCompile("^(.*)%(.*):([0-9]+)$") + + if re.MatchString(ssmarg) == false { + usage() + } + + ssm := re.FindAllStringSubmatch(ssmarg, -1)[0] + source := ssm[1] + group := ssm[2] + port := ssm[3] + + var bindif string + allnets, _ := net.Interfaces() + + if len(allnets) == 0 { + fmt.Printf("Did not find any network interfaces\n") + return + } else if len(allnets) == 1 { + // Only one interface available so use that. + bindif = allnets[0].Name + } else { + bindif = allnets[1].Name + } + + if len(arguments) == 4 { + switch arguments[2] { + case "-i": + bindif = arguments[3] + default: + fmt.Printf("INVALID ARG: %v\n", arguments[2]) + usage() + } + + } + + ssmif, err := net.InterfaceByName(bindif) + if err != nil { + fmt.Printf("Could not bind to interface '%v'\n", bindif) + return + } + + c, err := net.ListenPacket("udp4", "0.0.0.0:"+port) + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("Server listening on UDP port %v\nJoining multicast (S,G)=%v,%v w/iface %v\n", port, source, group, bindif) + + defer c.Close() + + p := ipv4.NewPacketConn(c) + + ssmsource := net.UDPAddr{IP: net.ParseIP(source)} + ssmgroup := net.UDPAddr{IP: net.ParseIP(group)} + + if err := p.JoinSourceSpecificGroup(ssmif, &ssmgroup, &ssmsource); err != nil { + // error handling + fmt.Println(err) + return + } + + b := make([]byte, 9000) + var index int32 + var last_index int32 + index = 0 + last_index = 0 + first_packet := true + packet_count := 0 + var stream_start time.Time + packetSize := 0 + + for { + n, _, _, err := p.ReadFrom(b) + if err != nil { + // error handling + fmt.Println(err) + return + } + if n != 0 { + + packet_count++ + index = int32(binary.BigEndian.Uint32(b[0:4])) + if index < 0 { + // end of stream + fmt.Printf("!EOS [i:%v]\n", index) + first_packet = true + packet_count = 0 + last_index = 0 + index = 0 + continue + } + + if first_packet { + fmt.Printf("S: %v", index) + first_packet = false + stream_start = time.Now() + } else if index == (last_index + 1) { + fmt.Printf("\033[32m!\033[0m") + } else if index < last_index { + fmt.Printf("\033[34m<\033[0m") + } else if index > (last_index + 1) { + fmt.Printf("\033[36m>\033[0m") + } else { + fmt.Printf("\033[31m.\033[0m") + } + last_index = index + + if n != packetSize { + fmt.Printf("PS[%v]", n) + packetSize = n + } + + if time.Since(stream_start)/time.Second >= 5 { + fmt.Printf("[%vpps]", packet_count/5) + stream_start = time.Now() + packet_count = 0 + } + } else { + break + } + } + + if err := p.LeaveSourceSpecificGroup(ssmif, &ssmgroup, &ssmsource); err != nil { + // error handling + fmt.Println(err) + return + } +} diff --git a/sender/ssmd.go b/sender/ssmd.go new file mode 100644 index 0000000000000000000000000000000000000000..2631ffec486c989c784fefaa407746e269f0e285 --- /dev/null +++ b/sender/ssmd.go @@ -0,0 +1,94 @@ +package main + +import ( + //"encoding/binary" + "encoding/hex" + "fmt" + "log" + "net" + "os" + "regexp" + "time" + + "golang.org/x/net/ipv4" +) + +func usage() { + fmt.Println("USAGE: ssmd <source>%<group>:<port>") + os.Exit(0) +} + +func main() { + arguments := os.Args + if len(arguments) < 2 { + usage() + } + + /* Process the SSM group join argument */ + + ssmarg := arguments[1] + re := regexp.MustCompile("^(.*)%(.*):([0-9]+)$") + + if re.MatchString(ssmarg) == false { + usage() + } + + ssm := re.FindAllStringSubmatch(ssmarg, -1)[0] + + source := ssm[1] + group := ssm[2] + port := ssm[3] + + dst, err := net.ResolveUDPAddr("udp", group+":"+port) + + if err != nil { + log.Fatal(err) + } + //dst := &net.UDPAddr{IP: net.ParseIP(group), Port: } + + src, err := net.ListenPacket("udp4", source+":55214") + + if err != nil { + log.Fatal(err) + } + + defer src.Close() + + p := ipv4.NewPacketConn(src) + + p.SetTOS(0x0) + p.SetMulticastTTL(32) + + data := make([][]byte, 11) + + data[0], _ = hex.DecodeString("0121000000000000000000000000000000000000f0000000a0000000000000000000000399d20000000000000000000000000a0afa0254534c2d5445522d3100") + data[1], _ = hex.DecodeString("0121000000000000000000000000000000000000f0000000a0000000000000000000000399d20000000000000000000000000a0afa0254534c2d5445522d3100") + data[2], _ = hex.DecodeString("0121000000000000000000000000000000000000f0000000a0000000000000000000000399d20000000000000000000000000a0afa0254534c2d5445522d3100") + data[3], _ = hex.DecodeString("0121000000000000000000000000000000000000f0000000a0000000000000000000000399d20000000000000000000000000a0afa0254534c2d5445522d3100") + data[4], _ = hex.DecodeString("0121000000000000000000000000000000000000f0000000a0000000000000000000000399d20000000000000000000000000a0afa0254534c2d5445522d3100") + data[5], _ = hex.DecodeString("0121000000000000000000000000000000000000f0000000a0000000000000000000000399d20000000000000000000000000a0afa0254534c2d5445522d3100") + data[6], _ = hex.DecodeString("012099d20000000000000000000000000a0afa02f00000012000000000aaaaaa000000000000001010ffffff000005dc00000000000a54534c2d5445522d31000000") + data[7], _ = hex.DecodeString("010199d20000000000000000000000000a0afa02f000000220000001002aaaaaea660000c00000000000000099d20000000000000000000000000a0afa020000003105020000003162e7b95400000000000000000000400000000000e8dfde0212670000000186a0c654534c2d5445522d3100") + data[8], _ = hex.DecodeString("012099d20000000000000000000000000a0afa02f00000032000000100aaaaaaea6600000000001010ffffff000005dc00000000000a54534c2d5445522d310000000104eb070000000000000000000000000a0afd030104ee4c0000000000000000000000000a0aff030104eb150000000000000000000000000a00000a") + data[9], _ = hex.DecodeString("010199d20000000000000000000000000a0afa02f000000420000002002aaaaaea660000c00000010000000099d20000000000000000000000000a0afa020000001a05700000001a03e80000000000000000000000003e286f7927b0") + data[10], _ = hex.DecodeString("012099d20000000000000000000000000a0afa02f00000052000000200aaaaaaea6600000000001010ffffff000005dc00000000000a54534c2d5445522d31000000") + + packetSize := 0 + + packetId := 0 + + for { + fmt.Printf("!") + n, _ := p.WriteTo(data[packetId], nil, dst) + if n != packetSize { + fmt.Printf("PS[%v]", n) + packetSize = n + } + if packetId == 10 { + packetId = 0 + } else { + packetId++ + } + time.Sleep(500 * time.Millisecond) + } +} diff --git a/ssm.go b/ssm.go deleted file mode 100644 index 6d06ed87284589d3fb94283f7b3e143e27325416..0000000000000000000000000000000000000000 --- a/ssm.go +++ /dev/null @@ -1,153 +0,0 @@ -package main - -import ( - //"encoding/binary" - "fmt" - "net" - "os" - "encoding/binary" - //"runtime" - "time" - "regexp" - "golang.org/x/net/ipv4" - -) - -func usage() { - fmt.Println("USAGE: ssm <source>%<group>:<port>\n") - os.Exit(0) -} - -func main() { - arguments := os.Args - if len(arguments) < 2 { - usage() - } - - /* Process the SSM group join argument */ - - ssmarg := arguments[1] - re := regexp.MustCompile("^(.*)%(.*):([0-9]+)$") - - if re.MatchString(ssmarg) == false { - usage() - } - - ssm := re.FindAllStringSubmatch(ssmarg, -1)[0] - source := ssm[1] - group := ssm[2] - port := ssm[3] - - var bindif string - allnets, _ := net.Interfaces() - - if(len(allnets) == 0) { - fmt.Printf("Did not find any network interfaces\n") - return - } else if (len(allnets) == 1) { - // Only one interface available so use that. - bindif = allnets[0].Name - } else { - bindif = allnets[1].Name - } - - if len(arguments) == 4 { - switch(arguments[2]) { - case "-i": - bindif = arguments[3] - default: - fmt.Printf("INVALID ARG: %v\n", arguments[2]) - usage() - } - - } - - ssmif, err := net.InterfaceByName(bindif) - if err != nil { - fmt.Printf("Could not bind to interface '%v'\n", bindif) - return - } - - c, err := net.ListenPacket("udp4", "0.0.0.0:" + port) - - if err != nil { - fmt.Println(err) - return - } - - fmt.Printf("Server listening on UDP port %v\nJoining multicast (S,G)=%v,%v w/iface %v\n", port, source, group, bindif) - - defer c.Close() - - p := ipv4.NewPacketConn(c) - - ssmsource := net.UDPAddr{IP: net.ParseIP(source)} - ssmgroup := net.UDPAddr{IP: net.ParseIP(group)} - - if err := p.JoinSourceSpecificGroup(ssmif, &ssmgroup, &ssmsource); err != nil { - // error handling - fmt.Println(err) - return - } - - b := make([]byte, 1500) - var index int32 - var last_index int32 - index = 0 - last_index = 0 - first_packet := true - packet_count := 0 - var stream_start time.Time - - - for { - n, _, _, err := p.ReadFrom(b) - if err != nil { - // error handling - fmt.Println(err) - return - } - if n != 0 { - packet_count++ - index = int32(binary.BigEndian.Uint32(b[0:4])) - if index < 0 { - // end of stream - fmt.Printf("!EOS [i:%v]\n", index) - first_packet = true - packet_count = 0 - last_index = 0 - index = 0 - continue - } - - if first_packet { - fmt.Printf("S: %v", index) - first_packet = false - stream_start = time.Now() - } else if index == (last_index + 1){ - fmt.Printf("\033[32m!\033[0m") - } else if index < last_index { - fmt.Printf("\033[34m<\033[0m") - } else if index > (last_index + 1) { - fmt.Printf("\033[36m>\033[0m") - } else { - fmt.Printf("\033[31m.\033[0m") - } - last_index = index - - if time.Since(stream_start)/time.Second >= 5 { - fmt.Printf("[%vpps]", packet_count/5) - stream_start = time.Now() - packet_count = 0 - } - } else { - break - } - } - - if err := p.LeaveSourceSpecificGroup(ssmif, &ssmgroup, &ssmsource); err != nil { - // error handling - fmt.Println(err) - return - } -} \ No newline at end of file