1/* 2NNCP -- Node to Node copy, utilities for store-and-forward data exchange 3Copyright (C) 2016-2021 Sergey Matveev <stargrave@stargrave.org> 4 5This program is free software: you can redistribute it and/or modify 6it under the terms of the GNU General Public License as published by 7the Free Software Foundation, version 3 of the License. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12GNU General Public License for more details. 13 14You should have received a copy of the GNU General Public License 15along with this program. If not, see <http://www.gnu.org/licenses/>. 16*/ 17 18// Parse raw NNCP packet. 19package main 20 21import ( 22 "bufio" 23 "bytes" 24 "flag" 25 "fmt" 26 "io" 27 "log" 28 "os" 29 30 xdr "github.com/davecgh/go-xdr/xdr2" 31 "github.com/klauspost/compress/zstd" 32 "go.cypherpunks.ru/nncp/v8" 33) 34 35func usage() { 36 fmt.Fprintf(os.Stderr, nncp.UsageHeader()) 37 fmt.Fprintf(os.Stderr, "nncp-pkt -- parse raw packet\n\n") 38 fmt.Fprintf(os.Stderr, "Usage: %s [options]\nOptions:\n", os.Args[0]) 39 flag.PrintDefaults() 40 fmt.Fprintln(os.Stderr, "Packet is read from stdin.") 41} 42 43func doPlain(ctx *nncp.Ctx, pkt nncp.Pkt, dump, decompress bool) { 44 if dump { 45 bufW := bufio.NewWriter(os.Stdout) 46 var r io.Reader 47 r = bufio.NewReader(os.Stdin) 48 if decompress { 49 decompressor, err := zstd.NewReader(r) 50 if err != nil { 51 log.Fatalln(err) 52 } 53 r = decompressor 54 } 55 if _, err := io.Copy(bufW, r); err != nil { 56 log.Fatalln(err) 57 } 58 if err := bufW.Flush(); err != nil { 59 log.Fatalln(err) 60 } 61 return 62 } 63 payloadType := "unknown" 64 switch pkt.Type { 65 case nncp.PktTypeFile: 66 payloadType = "file" 67 case nncp.PktTypeFreq: 68 payloadType = "file request" 69 case nncp.PktTypeExec: 70 payloadType = "exec compressed" 71 case nncp.PktTypeTrns: 72 payloadType = "transitional" 73 case nncp.PktTypeExecFat: 74 payloadType = "exec uncompressed" 75 case nncp.PktTypeArea: 76 payloadType = "area" 77 } 78 var path string 79 switch pkt.Type { 80 case nncp.PktTypeExec, nncp.PktTypeExecFat: 81 path = string(bytes.Replace( 82 pkt.Path[:pkt.PathLen], []byte{0}, []byte(" "), -1, 83 )) 84 case nncp.PktTypeTrns: 85 path = nncp.Base32Codec.EncodeToString(pkt.Path[:pkt.PathLen]) 86 node, err := ctx.FindNode(path) 87 if err == nil { 88 path = fmt.Sprintf("%s (%s)", path, node.Name) 89 } 90 case nncp.PktTypeArea: 91 path = nncp.Base32Codec.EncodeToString(pkt.Path[:pkt.PathLen]) 92 if areaId, err := nncp.AreaIdFromString(path); err == nil { 93 path = fmt.Sprintf("%s (%s)", path, ctx.AreaName(areaId)) 94 } 95 default: 96 path = string(pkt.Path[:pkt.PathLen]) 97 } 98 fmt.Printf( 99 "Packet type: plain\nPayload type: %s\nNiceness: %s (%d)\nPath: %s\n", 100 payloadType, nncp.NicenessFmt(pkt.Nice), pkt.Nice, path, 101 ) 102 return 103} 104 105func doEncrypted( 106 ctx *nncp.Ctx, 107 pktEnc nncp.PktEnc, 108 dump bool, 109 beginning []byte, 110) { 111 senderName := "unknown" 112 senderNode := ctx.Neigh[*pktEnc.Sender] 113 if senderNode != nil { 114 senderName = senderNode.Name 115 } 116 117 recipientName := "unknown" 118 var area *nncp.Area 119 recipientNode := ctx.Neigh[*pktEnc.Recipient] 120 if recipientNode == nil { 121 area = ctx.AreaId2Area[nncp.AreaId(*pktEnc.Recipient)] 122 if area != nil { 123 recipientName = "area " + area.Name 124 } 125 } else { 126 recipientName = recipientNode.Name 127 } 128 129 if !dump { 130 fmt.Printf(`Packet type: encrypted 131Niceness: %s (%d) 132Sender: %s (%s) 133Recipient: %s (%s) 134`, 135 nncp.NicenessFmt(pktEnc.Nice), pktEnc.Nice, 136 pktEnc.Sender, senderName, 137 pktEnc.Recipient, recipientName, 138 ) 139 return 140 } 141 if ctx.Self == nil { 142 log.Fatalln("Config lacks private keys") 143 } 144 bufW := bufio.NewWriter(os.Stdout) 145 var err error 146 if area == nil { 147 _, _, _, err = nncp.PktEncRead( 148 ctx.Self, ctx.Neigh, 149 io.MultiReader(bytes.NewReader(beginning), bufio.NewReader(os.Stdin)), 150 bufW, senderNode != nil, nil, 151 ) 152 } else { 153 areaNode := nncp.NodeOur{Id: new(nncp.NodeId), ExchPrv: new([32]byte)} 154 copy(areaNode.Id[:], area.Id[:]) 155 copy(areaNode.ExchPrv[:], area.Prv[:]) 156 _, _, _, err = nncp.PktEncRead( 157 &areaNode, ctx.Neigh, 158 io.MultiReader(bytes.NewReader(beginning), bufio.NewReader(os.Stdin)), 159 bufW, senderNode != nil, nil, 160 ) 161 } 162 if err != nil { 163 log.Fatalln(err) 164 } 165 if err = bufW.Flush(); err != nil { 166 log.Fatalln(err) 167 } 168} 169 170func main() { 171 var ( 172 overheads = flag.Bool("overheads", false, "Print packet overheads") 173 dump = flag.Bool("dump", false, "Write decrypted/parsed payload to stdout") 174 decompress = flag.Bool("decompress", false, "Try to zstd decompress dumped data") 175 cfgPath = flag.String("cfg", nncp.DefaultCfgPath, "Path to configuration file") 176 version = flag.Bool("version", false, "Print version information") 177 warranty = flag.Bool("warranty", false, "Print warranty information") 178 ) 179 log.SetFlags(log.Lshortfile) 180 flag.Usage = usage 181 flag.Parse() 182 if *warranty { 183 fmt.Println(nncp.Warranty) 184 return 185 } 186 if *version { 187 fmt.Println(nncp.VersionGet()) 188 return 189 } 190 191 ctx, err := nncp.CtxFromCmdline(*cfgPath, "", "", false, false, false, false) 192 if err != nil { 193 log.Fatalln("Error during initialization:", err) 194 } 195 196 if *overheads { 197 fmt.Printf( 198 "Plain: %d\nEncrypted: %d\nSize: %d\n", 199 nncp.PktOverhead, 200 nncp.PktEncOverhead, 201 nncp.PktSizeOverhead, 202 ) 203 return 204 } 205 206 beginning := make([]byte, nncp.PktOverhead) 207 if _, err := io.ReadFull(os.Stdin, beginning[:nncp.PktEncOverhead]); err != nil { 208 log.Fatalln("Not enough data to read") 209 } 210 var pktEnc nncp.PktEnc 211 if _, err := xdr.Unmarshal(bytes.NewReader(beginning), &pktEnc); err == nil { 212 switch pktEnc.Magic { 213 case nncp.MagicNNCPEv1.B: 214 log.Fatalln(nncp.MagicNNCPEv1.TooOld()) 215 case nncp.MagicNNCPEv2.B: 216 log.Fatalln(nncp.MagicNNCPEv2.TooOld()) 217 case nncp.MagicNNCPEv3.B: 218 log.Fatalln(nncp.MagicNNCPEv3.TooOld()) 219 case nncp.MagicNNCPEv4.B: 220 log.Fatalln(nncp.MagicNNCPEv4.TooOld()) 221 case nncp.MagicNNCPEv5.B: 222 log.Fatalln(nncp.MagicNNCPEv5.TooOld()) 223 case nncp.MagicNNCPEv6.B: 224 doEncrypted(ctx, pktEnc, *dump, beginning[:nncp.PktEncOverhead]) 225 return 226 } 227 } 228 229 if _, err := io.ReadFull(os.Stdin, beginning[nncp.PktEncOverhead:]); err != nil { 230 log.Fatalln("Not enough data to read") 231 } 232 var pkt nncp.Pkt 233 if _, err := xdr.Unmarshal(bytes.NewReader(beginning), &pkt); err == nil { 234 switch pkt.Magic { 235 case nncp.MagicNNCPPv1.B: 236 log.Fatalln(nncp.MagicNNCPPv1.TooOld()) 237 case nncp.MagicNNCPPv2.B: 238 log.Fatalln(nncp.MagicNNCPPv2.TooOld()) 239 case nncp.MagicNNCPPv3.B: 240 doPlain(ctx, pkt, *dump, *decompress) 241 return 242 } 243 } 244 log.Fatalln("Unable to determine packet type") 245} 246