Ejemplo n.º 1
0
func loadI2PKey(fname string) (key i2p.I2PKeys, err error) {
	data, err := ioutil.ReadFile(fname)
	if err == nil {
		parts := strings.Split(string(data), "\n")
		key = i2p.NewKeys(i2p.I2PAddr(parts[0]), parts[1])
	}
	return
}
Ejemplo n.º 2
0
func Run() {
	// defaults
	fname := "samtun.json"
	only_print_dest := false
	if len(os.Args) > 1 {
		if os.Args[1] == "-h" || os.Args[1] == "--help" {
			// print usage and return
			fmt.Fprintf(os.Stdout, "usage: %s [config.json]\n", os.Args[0])
			return
		} else if os.Args[1] == "--dest" {
			// print out destination
			only_print_dest = true
		} else {
			fname = os.Args[1]
		}
	}
	if !checkfile(fname) {
		// generate a config we don't have it there
		conf := genConfig(fname)
		conf.Save(fname)
	}
	conf, err := loadConfig(fname)
	if err == nil {
		// we are configured correctly
		ip, _, err := net.ParseCIDR(conf.Addr)
		if err != nil {
			log.Println("invalid address", conf.Addr)
			return
		}
		Map := make(addrMap)
		// we have a sam connection
		var keys sam3.I2PKeys
		if !checkfile(conf.Keyfile) {

			log.Println("connecting to", conf.Sam)
			sam, err := sam3.NewSAM(conf.Sam)
			if err == nil {
				// we have not generated private keys yet
				log.Println("generating keys")
				keys, err = sam.NewKeys()
				sam.Close()
				ioutil.WriteFile(conf.Keyfile, []byte(keys.String()+" "+keys.Addr().String()), 0600)
				// load addr map if it is there
				if checkfile(conf.MapFile) {
					Map, _ = loadAddrMap(conf.MapFile)
				}
				b32 := keys.Addr().Base32()
				Map[b32] = []string{conf.Addr}
				err = saveAddrMap(conf.MapFile, Map)
				if err != nil {
					log.Println("failed to save address map", err)
					return
				}
			} else {
				log.Fatal(err)
			}
		}
		key_bytes, err := ioutil.ReadFile(conf.Keyfile)
		if err == nil {
			// read the keys
			key_str := string(key_bytes)
			privkey := strings.Split(key_str, " ")[0]
			pubkey := strings.Split(key_str, " ")[1]
			keys := sam3.NewKeys(sam3.I2PAddr(pubkey), privkey)
			log.Println("our destination is", keys.Addr().Base32())
			if only_print_dest {
				return
			}
			// load address map
			Map, err = loadAddrMap(conf.MapFile)
			if err != nil {
				log.Fatal(err)
			}
			// create our datagram session
			log.Println("creating session")

			var opts []string

			// set up sam options
			if conf.SamOpts == nil {
				opts = sam3.Options_Small
			} else {
				for k, v := range conf.SamOpts {
					opts = append(opts, fmt.Sprintf("%s=%s", k, v))
				}
			}
			sam, err := sam3.NewSAM(conf.Sam)
			if err == nil {
				dg, err := sam.NewDatagramSession(conf.Session, keys, opts, 0)
				defer dg.Close()
				if err == nil {
					log.Println("session made")
					ourAddr, err := sam.Lookup("ME")
					if err != nil {
						log.Println("failed to lookup our own destination")
						return
					}
					log.Println("we are", ourAddr.Base32())
					iface, err := newTun(conf.Ifname, ip.String(), conf.Netmask, conf.MTU)
					if err != nil {
						log.Fatalf("failed to create network interface %s", err.Error())
					}
					defer iface.Close()
					tunpkt_inchnl := make(chan []byte)
					//tunpkt_outchnl := make(chan []byte)
					sampkt_inchnl := make(chan linkMessage)
					//sampkt_outchnl := make(chan linkMessage)
					// read packets from tun
					go func() {
						for {
							pktbuff := make([]byte, conf.MTU+64)
							n, err := iface.Read(pktbuff[:])
							if err == nil {
								tunpkt_inchnl <- pktbuff[:n]
							} else {
								log.Println("error while reading tun packet", err)
								time.Sleep(time.Second)
							}
						}
					}()

					// read packets from sam
					go func() {
						for {
							pktbuff := make([]byte, conf.MTU+64)
							n, from, err := dg.ReadFrom(pktbuff)
							if err == nil {
								// lookup ip from address map
								if Map.AllowDest(from.Base32()) {
									// got from sam
									sampkt_inchnl <- linkMessage{pkt: pktbuff[:n], addr: from}
								} else {
									// unwarrented
									log.Println("unwarrented packet from", from.Base32())
								}
							} else {
								log.Println("error while reading sam packet", err)
								close(sampkt_inchnl)
								return
							}
						}
					}()
					lookup_chnl := make(chan string, 8)
					lookup_result_chnl := make(chan sam3.I2PAddr, 8)

					go func() {
						// lookup destinations goroutine
						for {
							b32 := <-lookup_chnl
							log.Println("lookup", b32)
							dest, err := sam.Lookup(b32)
							if err == nil {
								log.Println("found", b32)
								lookup_result_chnl <- dest
							}
						}
					}()

					done_chnl := make(chan bool)
					// sam send routine
					go func() {
						// b32 -> b64 cache
						dest_cache := make(map[string]sam3.I2PAddr)
						for {
							select {
							case addr, ok := <-lookup_result_chnl:
								if ok {
									dest_cache[addr.Base32()] = addr
								}

							case data, ok := <-tunpkt_inchnl:
								if ok {
									pkt := ipPacket(data)
									dst := pkt.Dst()
									b32 := Map.B32(dst)
									if len(b32) == 0 {
										log.Println("cannot send packet to", dst, "unknown endpoint")
									} else {
										dest, ok := dest_cache[b32]
										if ok {
											_, err := dg.WriteTo(pkt[:], dest)
											if err == nil {
												// we gud
											} else {
												log.Println("error writing to remote destination", err)
												done_chnl <- true
												return
											}
										} else {
											// cache miss
											// TODO: deadlock
											lookup_chnl <- b32
										}
									}
								} else {
									done_chnl <- true
									return
								}
							}
						}
					}()

					// write tun packet routine
					go func() {
						for {
							msg, ok := <-sampkt_inchnl
							if ok {
								pkt := Map.filterMessage(msg, ourAddr)
								if pkt == nil {
									// invalid frame D:
									log.Println("invalid frame from", msg.addr.Base32())
								} else {
									_, err := iface.Write(pkt)
									if err == nil {
										// we gud
									} else {
										log.Println("error writing to tun interface", err)
										done_chnl <- true
										return
									}
								}
							} else {
								done_chnl <- true
								return
							}
						}
					}()
					<-done_chnl
					log.Println("closing")
				} else {
					log.Fatal(err)
				}
			} else {
				log.Fatal(err)
			}
		} else {
			log.Fatal(err)
		}
	} else {
		log.Fatal(err)
	}
}