func testBuffer() { var b bytes.Buffer check(b.String(), "") // String() on fresh variable b.Reset() // Reset() on fresh variable check(b.String(), "") // String() after Reset() b.Reset() // Reset() after Reset() check(b.String(), "") check(b.Len(), 0) // same tests as above with pointer b2 := &bytes.Buffer{} check(b2.String(), "") b2.Reset() check(b2.String(), "") b2.Reset() check(b2.String(), "") check(b2.Len(), 0) b2.WriteString("Dies ist ein Test!") check(b2.String(), "Dies ist ein Test!") check(b2.Len(), 18) n, err := b.Write(nil) check(n, 0) check(err, nil) check(b.String(), "") n, err = b.Write([]byte{}) check(n, 0) check(err, nil) check(b.String(), "") check(b.Pointer(), nil) check(b.Capacity(), 0) check(b.Len(), 0) func() { defer func() { check(recover(), bytes.ErrTooLarge) }() b.Grow(-1) }() n, err = b.Write([]byte{'a'}) check(n, 1) check(err, nil) check(b.String(), "a") check(b.Capacity() >= 1, true) check(b.Len(), 1) check(b.Pointer() != nil, true) check(b.Grow(11), 1) check(b.Capacity() >= 12, true) c := b.Capacity() p := b.Pointer() check(b.Grow(11), 1) // should not cause actual growth check(b.Pointer(), p) check(b.Capacity(), c) check(b.Len(), 1) ((*[2]byte)(b.Pointer()))[1] = 'z' check(b.Contains("z"), false) n, err = b.WriteString("Hallo") check(n, 5) check(err, nil) check(b.String(), "aHallo") check(b.Pointer(), p) check(b.Capacity(), c) check(b.Len(), 6) b.Reset() check(b.String(), "") check(b.Pointer(), nil) check(b.Capacity(), 0) check(b.Contains(""), true) check(b.Contains("a"), false) b.WriteString("Hallo") b.WriteByte(' ') b.Write([]byte{'d', 'i', 'e', 's'}) b.WriteByte(' ') b.WriteString("ist ") b.WriteString("ein ") b.Write([]byte("Test")) check(b.String(), "Hallo dies ist ein Test") check(b.Contains("Hallo dies ist ein Test"), true) check(b.Contains("Test"), true) check(b.Contains("Hallo"), true) check(b.Contains("allo"), true) check(b.Contains(""), true) check(b.Split(" "), []string{"Hallo", "dies", "ist", "ein", "Test"}) check(b.Split("X"), []string{"Hallo dies ist ein Test"}) check(b.Split("Hallo dies ist ein Test"), []string{"", ""}) check(b.Split("H"), []string{"", "allo dies ist ein Test"}) check(b.Split("Test"), []string{"Hallo dies ist ein ", ""}) check(b.Split("es"), []string{"Hallo di", " ist ein T", "t"}) b.Reset() b.WriteString(" \n\t Hallo \t\v\n") check(b.Len(), 15) p = b.Pointer() b.TrimSpace() check(b.String(), "Hallo") check(b.Len(), 5) check(b.Pointer(), p) b.Reset() b.WriteString(" \n\t \t\v\n") check(b.Len(), 10) b.TrimSpace() check(b.Pointer(), nil) check(b.Len(), 0) check(b.Capacity(), 0) b.TrimSpace() check(b.Pointer(), nil) check(b.Len(), 0) check(b.Capacity(), 0) b.Reset() b.WriteString(" \n\t Hallo") check(b.Len(), 10) p = b.Pointer() b.TrimSpace() check(b.String(), "Hallo") check(b.Len(), 5) check(b.Pointer(), p) b.Reset() b.WriteString("Hallo \t\v\n") check(b.Len(), 10) p = b.Pointer() b.TrimSpace() check(b.String(), "Hallo") check(b.Len(), 5) check(b.Pointer(), p) b.Reset() b.WriteString(" ") check(b.Len(), 1) b.TrimSpace() check(b.Pointer(), nil) check(b.Len(), 0) check(b.Capacity(), 0) b.Reset() b.WriteString("Der Cottbuser Postkutscher kotzt in den Cottbuser Postkotzkasten") n = b.Len() c = b.Capacity() p = b.Pointer() b.Trim(-10, 2000) check(b.Len(), n) check(b.Capacity(), c) check(b.Pointer(), p) b.Trim(2000, -10) check(b.Len(), 0) check(b.Capacity(), 0) check(b.Pointer(), nil) b.WriteString("Der Cottbuser Postkutscher kotzt in den Cottbuser Postkotzkasten") b.Trim(4, 4) check(b.Len(), 0) check(b.Capacity(), 0) check(b.Pointer(), nil) b.WriteString("Der Cottbuser Postkutscher kotzt in den Cottbuser Postkotzkasten") n = b.Len() c = b.Capacity() p = b.Pointer() b.Trim(0, b.Len()-6) check(b.Len(), n-6) check(b.Capacity(), c) check(b.Pointer(), p) check(b.String(), "Der Cottbuser Postkutscher kotzt in den Cottbuser Postkotz") b.Trim(27, b.Len()) check(b.Len(), n-6-27) check(b.Capacity(), c) check(b.Pointer(), p) check(b.String(), "kotzt in den Cottbuser Postkotz") b.Trim(1, b.Len()-1) check(b.Len(), n-6-27-2) check(b.Capacity(), c) check(b.Pointer(), p) check(b.String(), "otzt in den Cottbuser Postkot") b.Reset() b.Write0(-1) b.Write0(-100) b.Write0(0) check(b.Len(), 0) check(b.Capacity(), 0) check(b.Pointer(), nil) b.Write0(1) check(b.Len(), 1) check(b.Capacity(), 1) check(b.Bytes(), []byte{0}) b.WriteByte(111) b.Write0(1) b.WriteByte(222) b.Write0(2) b.WriteByte(99) check(b.Len(), 7) check(b.Bytes(), []byte{0, 111, 0, 222, 0, 0, 99}) b2.Reset() slices := [][]byte{} total := 0 numfakeerrs := 0 for total < 100000 { c = rand.Intn(30000) total += c sl := make([]byte, c) for i := range sl { sl[i] = byte(rand.Intn(256)) } slices = append(slices, sl) b2.Write(sl) if total/30000 > numfakeerrs { slices = append(slices, nil) numfakeerrs++ } } check(numfakeerrs, 3) slcopy := make([][]byte, len(slices)) copy(slcopy, slices) slret := &sliceReturner{Slices: slcopy} b.Reset() check(b.Capacity(), 0) check(b.Len(), 0) check(b.Pointer(), nil) n = 0 for i := 0; i < numfakeerrs; i++ { n64, err := b.ReadFrom(slret) n += int(n64) check(err, FakeError) } n64, err := b.ReadFrom(slret) n += int(n64) check(err, nil) check(n, total) check(b.Capacity() > b.Len(), true) check(b.Len(), total) contents := b.Bytes() contents2 := b2.Bytes() check(len(contents), len(contents2)) n = 0 for i := range contents { if contents[i] != contents2[i] { break } n++ } check(n, total) b2.Reset() for i := range slices { for k := range slices[i] { slices[i][k] = 11 } n, err = b.Read(slices[i]) check(n, len(slices[i])) check(err, nil) b2.Write(slices[i]) } check(b2.Len(), total) n, err = b.Read(slices[0]) check(n, 0) check(err, io.EOF) contents = b.Bytes() contents2 = b2.Bytes() check(len(contents), len(contents2)) n = 0 for i := range contents { if contents[i] != contents2[i] { break } n++ } check(n, total) b.WriteString("foo") foo := make([]byte, 10) n, err = b.Read(foo) check(n, 3) check(err, nil) check(string(foo[0:3]), "foo") n64, err = b.Seek(6700, 0) check(n64, 6700) check(err, nil) n64, err = b.Seek(-6000, 1) check(n64, 700) check(err, nil) n64, err = b.Seek(815, 1) check(n64, 1515) check(err, nil) n, err = b.Read(foo) check(n, len(foo)) check(err, nil) check(foo, b2.Bytes()[1515:1515+len(foo)]) n64, err = b.Seek(-3, 2) check(n64, total) check(err, nil) n, err = b.Read(foo) check(n, 3) check(err, nil) check(string(foo[0:3]), "foo") n64, err = b.Seek(999999, 0) check(n64, b.Len()) check(err, nil) n64, err = b.Seek(-3, 1) check(n64, total) check(err, nil) n, err = b.Read(foo) check(n, 3) check(err, nil) check(string(foo[0:3]), "foo") n64, err = b.Seek(-815, 0) check(n64, 0) check(err, nil) n, err = b.Read(foo) check(n, len(foo)) check(err, nil) check(foo, b2.Bytes()[0:len(foo)]) }
// Takes a possibly encrypted message in buf and processes it, returning a reply. // context is the security context. // Returns: // buffer containing the reply to return (MUST BE FREED BY CALLER VIA Reset()!) // disconnect == true if connection should be terminated due to error // // NOTE: buf IS NOT FREED BY THIS FUNCTION BUT ITS CONTENTS ARE CHANGED! func ProcessEncryptedMessage(buf *bytes.Buffer, context *security.Context) (reply *bytes.Buffer, disconnect bool) { if buf.Len() > 4096 { util.Log(2, "DEBUG! Processing LONG message: (truncated)%v\n.\n.\n.\n%v", string(buf.Bytes()[0:2048]), string(buf.Bytes()[buf.Len()-2048:])) } else { util.Log(2, "DEBUG! Processing message: %v", buf.String()) } for attempt := 0; attempt < 4; attempt++ { if attempt != 0 && config.TLSRequired { util.Log(1, "INFO! [SECURITY] TLS-only mode => Decryption with old protocol will not be attempted") //NOTE: This prevents the last ditch attempt to decrypt with all known // server and client keys. This attempt might still have produced a // result in case the connecting party is pre-TLS and we happen to // have its key in our database (from a time before our server was // configured to be TLS-only). However if the admin configured our // server to be TLS-only (by not putting any keys // in the config) we assume that he does not want pre-TLS // parties to connect. break } var keys_to_try []string switch attempt { case 0: keys_to_try = config.ModuleKeys case 1: host := context.PeerID.IP.String() { keys_to_try = append(db.ServerKeys(host), db.ClientKeys(host)...) if host == "127.0.0.1" { // make sure we find the key even if registered under our external IP address keys_to_try = append(db.ServerKeys(config.IP), db.ClientKeys(config.IP)...) } } case 2: util.Log(1, "INFO! Last resort attempt to decrypt message from %v with all server keys", context.PeerID.IP) keys_to_try = db.ServerKeysForAllServers() case 3: util.Log(1, "INFO! Last resort attempt to decrypt message from %v with all client keys", context.PeerID.IP) keys_to_try = db.ClientKeysForAllClients() } for _, key := range keys_to_try { if security.GosaDecryptBuffer(buf, key) { if buf.Len() > 4096 { util.Log(2, "DEBUG! Decrypted LONG message from %v with key %v: (truncated)%v\n.\n.\n.\n%v", context.PeerID.IP, key, string(buf.Bytes()[0:2048]), string(buf.Bytes()[buf.Len()-2048:])) } else { util.Log(2, "DEBUG! Decrypted message from %v with key %v: %v", context.PeerID.IP, key, buf.String()) } // special case for CLMSG_save_fai_log because this kind of message // is so large and parsing it to XML doesn't really gain us anything. if buf.Contains("<CLMSG_save_fai_log>") { if handleServerMessage() { clmsg_save_fai_log(buf) } return &bytes.Buffer{}, false } xml, err := xml.StringToHash(buf.String()) if err != nil { util.Log(0, "ERROR! %v", err) return ErrorReplyBuffer(err), true } // At this point we have successfully decrypted and parsed the message return ProcessXMLMessage(xml, context, key) } } } // This part is only reached if none of the keys opened the message util.Log(0, "ERROR! Could not decrypt message from %v", context.PeerID.IP) // Maybe we got out of sync with the sender's encryption key // (e.g. by missing a new_key message). Try to re-establish communcation. ip := context.PeerID.IP.To4() if ip == nil { util.Log(0, "ERROR! Cannot convert sender address to IPv4 address: %v", context.PeerID.IP) } else { go tryToReestablishCommunicationWith(ip.String()) } return ErrorReplyBuffer("Could not decrypt message"), true }