func CheckC2(s1, c2 []byte) (uint32, error) { server_pos := rtmp.ValidateDigest(s1, 8, rtmp.GENUINE_FMS_KEY[:36]) if server_pos == 0 { server_pos = rtmp.ValidateDigest(s1, 772, rtmp.GENUINE_FMS_KEY[:36]) if server_pos == 0 { return 0, errors.New("Server response validating failed") } } digest, err := rtmp.HMACsha256(s1[server_pos:server_pos+rtmp.SHA256_DIGEST_LENGTH], rtmp.GENUINE_FP_KEY) rtmp.CheckError(err, "Get digest from s1 error") signature, err := rtmp.HMACsha256(c2[:rtmp.RTMP_SIG_SIZE-rtmp.SHA256_DIGEST_LENGTH], digest) rtmp.CheckError(err, "Get signature from c2 error") if bytes.Compare(signature, c2[rtmp.RTMP_SIG_SIZE-rtmp.SHA256_DIGEST_LENGTH:]) != 0 { return 0, errors.New("Server signature mismatch") } return server_pos, nil }
func main() { flag.Usage = func() { fmt.Fprintf(os.Stderr, "%s version[%s]\r\nUsage: %s [OPTIONS]\r\n", programName, version, os.Args[0]) flag.PrintDefaults() } flag.Parse() // listen listen, err := net.Listen("tcp", ":1935") if err != nil { log.Println("Listen error", err) os.Exit(-1) } defer listen.Close() for { iconn, err := listen.Accept() if err != nil { log.Println("Accept error", err) os.Exit(-1) } if iconn == nil { log.Println("iconn is nil") os.Exit(-1) } defer iconn.Close() // Handshake // C>>>P: C0+C1 ibr := bufio.NewReader(iconn) ibw := bufio.NewWriter(iconn) c0, err := ibr.ReadByte() if c0 != 0x03 { log.Printf("C>>>P: C0(0x%2x) != 0x03\n", c0) os.Exit(-1) } c1 := make([]byte, rtmp.RTMP_SIG_SIZE) _, err = io.ReadAtLeast(ibr, c1, rtmp.RTMP_SIG_SIZE) // Check C1 var clientDigestOffset uint32 if clientDigestOffset, err = CheckC1(c1, true); err != nil { log.Println("C>>>P: Test C1 err:", err) os.Exit(-1) } // P>>>S: Connect Server oconn, err := net.Dial("tcp", "192.168.20.111:1935") if err != nil { log.Println("P>>>S: Dial server err:", err) os.Exit(-1) } defer oconn.Close() obr := bufio.NewReader(oconn) obw := bufio.NewWriter(oconn) // P>>>S: C0+C1 if err = obw.WriteByte(c0); err != nil { log.Println("P>>>S: Write C0 err:", err) os.Exit(-1) } if _, err = obw.Write(c1); err != nil { log.Println("P>>>S: Write C1 err:", err) os.Exit(-1) } if err = obw.Flush(); err != nil { log.Println("P>>>S: Flush err:", err) os.Exit(-1) } // P<<<S: Read S0+S1+S2 s0, err := obr.ReadByte() if err != nil { log.Println("P<<<S: Read S0 err:", err) os.Exit(-1) } if c0 != 0x03 { log.Printf("P<<<S: S0(0x%2x) != 0x03\n", s0) os.Exit(-1) } s1 := make([]byte, rtmp.RTMP_SIG_SIZE) _, err = io.ReadAtLeast(obr, s1, rtmp.RTMP_SIG_SIZE) if err != nil { log.Println("P<<<S: Read S1 err:", err) os.Exit(-1) } s2 := make([]byte, rtmp.RTMP_SIG_SIZE) _, err = io.ReadAtLeast(obr, s2, rtmp.RTMP_SIG_SIZE) if err != nil { log.Println("P<<<S: Read S2 err:", err) os.Exit(-1) } // C<<<P: Send S0+S1+S2 if err = ibw.WriteByte(s0); err != nil { log.Println("C<<<P: Write S0 err:", err) os.Exit(-1) } if _, err = ibw.Write(s1); err != nil { log.Println("C<<<P: Write S1 err:", err) os.Exit(-1) } if _, err = ibw.Write(s2); err != nil { log.Println("C<<<P: Write S2 err:", err) os.Exit(-1) } if err = ibw.Flush(); err != nil { log.Println("C<<<P: Flush err:", err) os.Exit(-1) } // C>>>P: Read C2 c2 := make([]byte, rtmp.RTMP_SIG_SIZE) _, err = io.ReadAtLeast(ibr, c2, rtmp.RTMP_SIG_SIZE) // Check S2 server_pos := rtmp.ValidateDigest(s1, 8, rtmp.GENUINE_FP_KEY[:30]) if server_pos == 0 { server_pos = rtmp.ValidateDigest(s1, 772, rtmp.GENUINE_FP_KEY[:30]) if server_pos == 0 { log.Println("P<<<S: S1 position check error") os.Exit(-1) } } digest, err := rtmp.HMACsha256(c1[clientDigestOffset:clientDigestOffset+rtmp.SHA256_DIGEST_LENGTH], rtmp.GENUINE_FMS_KEY) rtmp.CheckError(err, "Get digest from c1 error") signature, err := rtmp.HMACsha256(s2[:rtmp.RTMP_SIG_SIZE-rtmp.SHA256_DIGEST_LENGTH], digest) rtmp.CheckError(err, "Get signature from s2 error") if bytes.Compare(signature, s2[rtmp.RTMP_SIG_SIZE-rtmp.SHA256_DIGEST_LENGTH:]) != 0 { log.Println("Server signature mismatch") os.Exit(-1) } digestResp, err := rtmp.HMACsha256(s1[server_pos:server_pos+rtmp.SHA256_DIGEST_LENGTH], rtmp.GENUINE_FP_KEY) rtmp.CheckError(err, "Generate C2 HMACsha256 digestResp") signatureResp, err := rtmp.HMACsha256(c2[:rtmp.RTMP_SIG_SIZE-rtmp.SHA256_DIGEST_LENGTH], digestResp) if bytes.Compare(signatureResp, c2[rtmp.RTMP_SIG_SIZE-rtmp.SHA256_DIGEST_LENGTH:]) != 0 { log.Println("C2 mismatch") os.Exit(-1) } // P>>>S: Send C2 if _, err = obw.Write(c2); err != nil { log.Println("P>>>S: Write C2 err:", err) os.Exit(-1) } if err = obw.Flush(); err != nil { log.Println("P>>>S: Flush err:", err) os.Exit(-1) } // Proxy go io.Copy(iconn, oconn) go io.Copy(oconn, iconn) } }