func injectDummy() { // Populate public keyring Pubring = keymgr.NewPubring( cfg.Files.Pubring, cfg.Files.Mlist2, ) Pubring.ImportPubring() dummy() }
// Start the server process. If run with --daemon, this will loop forever. func loopServer() (err error) { // Initialize the Public Keyring Pubring = keymgr.NewPubring( cfg.Files.Pubring, cfg.Files.Mlist2, ) // Fetch keyring and stats URLs timedURLFetch(cfg.Urls.Pubring, cfg.Files.Pubring) timedURLFetch(cfg.Urls.Mlist2, cfg.Files.Mlist2) // Initialize the Secret Keyring secret := keymgr.NewSecring(cfg.Files.Secring, cfg.Files.Pubkey) Pubring.ImportPubring() secret.ImportSecring() // Tell the secret keyring some basic info about this remailer secret.SetName(cfg.Remailer.Name) secret.SetAddress(cfg.Remailer.Address) secret.SetExit(cfg.Remailer.Exit) secret.SetValidity(cfg.Remailer.Keylife, cfg.Remailer.Keygrace) secret.SetVersion(version) // Create some dirs if they don't already exist createDirs() // Open the IDlog Trace.Printf("Opening ID Log: %s", cfg.Files.IDlog) // NewInstance takes the filename and entry validity in days IdDb = idlog.NewIDLog(cfg.Files.IDlog, cfg.Remailer.IDexp) defer IdDb.Close() // Open the chunk DB Trace.Printf("Opening the Chunk DB: %s", cfg.Files.ChunkDB) ChunkDb = OpenChunk(cfg.Files.ChunkDB) ChunkDb.SetExpire(cfg.Remailer.ChunkExpire) // Expire old entries in the ID Log idLogExpire() // Clean the chunk DB chunkClean() // Complain about poor configs nagOperator() // Run a key purge if purgeSecring(secret) == 0 { // If there are zero active keys, generate a new one. generateKeypair(secret) } else { /* If the operator changes his configuration, (such as upgrading to a new version or switching from exit to middleman), the published key will not match the configuration. This element of code writes a new key.txt file with current settings. This only needs to be done if we haven't generated a new key. */ refreshPubkey(secret) } Info.Printf("Secret keyring contains %d keys", secret.Count()) // Define triggers for timed events daily := time.Now() hourly := time.Now() dayOfMonth := time.Now().Day() oneDay := time.Duration(dayLength) * time.Second // Determine if this is a single run or the start of a Daemon runAsDaemon := cfg.Remailer.Daemon || flag_daemon // Actually start the server loop if runAsDaemon { Info.Printf("Starting YAMN server: %s", cfg.Remailer.Name) Info.Printf("Detaching Pool processing") go serverPoolOutboundSend() } else { Info.Printf("Performing routine remailer functions for: %s", cfg.Remailer.Name) } for { // Panic if the pooldir doesn't exist assertIsPath(cfg.Files.Pooldir) // Process the inbound Pool processInpool("i", secret) // Process the Maildir processMail(secret) // Midnight events if time.Now().Day() != dayOfMonth { Info.Println("Performing midnight events") // Remove expired keys from memory and rewrite a // secring file without expired keys. if purgeSecring(secret) == 0 { generateKeypair(secret) } // Expire entries in the ID Log idLogExpire() // Expire entries in the chunker chunkClean() // Report daily throughput and reset to zeros stats.report() stats.reset() // Reset dayOfMonth to today dayOfMonth = time.Now().Day() } // Daily events if time.Since(daily) > oneDay { Info.Println("Performing daily events") // Complain about poor configs nagOperator() // Reset today so we don't do these tasks for the next // 24 hours. daily = time.Now() } // Hourly events if time.Since(hourly) > time.Hour { Trace.Println("Performing hourly events") /* The following two conditions try to import new pubring and mlist2 URLs. If they fail, a warning is logged but no further action is taken. It's better to have old keys/stats than none. */ // Retrieve Mlist2 and Pubring URLs if cfg.Urls.Fetch { timedURLFetch( cfg.Urls.Pubring, cfg.Files.Pubring, ) timedURLFetch( cfg.Urls.Mlist2, cfg.Files.Mlist2, ) } // Test to see if the pubring.mix file has been updated if Pubring.KeyRefresh() { Trace.Printf( "Reimporting Public Keyring: %s", cfg.Files.Pubring, ) Pubring.ImportPubring() } // Report throughput stats.report() hourly = time.Now() } // Break out of the loop if we're not running as a daemon if !runAsDaemon { break } // And rest a while time.Sleep(60 * time.Second) } // End of server loop return }
// mixprep fetches the plaintext and prepares it for mix encoding func mixprep() { var err error err = os.MkdirAll(cfg.Files.Pooldir, 0700) if err != nil { panic(err) } // plain will contain the byte version of the plain text message var plain []byte // final is consistent across multiple copies so we define it early final := newSlotFinal() if len(flag_args) == 0 { //fmt.Println("Enter message, complete with headers. Ctrl-D to finish") plain, err = ioutil.ReadAll(os.Stdin) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } else if len(flag_args) == 1 { // A single arg should be the filename plain = readMessage(flag_args[0]) } else if len(flag_args) >= 2 { // Two args should be recipient and filename flag_to = flag_args[0] plain = readMessage(flag_args[1]) } // plainLen is the length of the plain byte message and can exceed // the total body size of the payload. plainLen := len(plain) if plainLen == 0 { fmt.Fprintln(os.Stderr, "No bytes in message") os.Exit(1) } // Download stats URLs if the time is right if cfg.Urls.Fetch { // Retrieve Mlist2 and Pubring URLs timedURLFetch(cfg.Urls.Pubring, cfg.Files.Pubring) timedURLFetch(cfg.Urls.Mlist2, cfg.Files.Mlist2) } // Create the Public Keyring Pubring = keymgr.NewPubring( cfg.Files.Pubring, cfg.Files.Mlist2, ) // Set the Use Expired flag to include remailers with expired keys as // candidates. if cfg.Stats.UseExpired { Pubring.UseExpired() } err = Pubring.ImportPubring() if err != nil { Warn.Printf("Pubring import failed: %s", cfg.Files.Pubring) return } // Read the chain from flag or config var in_chain []string if flag_chain == "" { in_chain = strings.Split(cfg.Stats.Chain, ",") } else { in_chain = strings.Split(flag_chain, ",") } if len(in_chain) == 0 { err = errors.New("Empty input chain") return } var cnum int // Chunk number var numc int // Number of chunks numc = int(math.Ceil(float64(plainLen) / float64(maxFragLength))) final.setNumChunks(numc) var exitnode string // Address of exit node (for multiple copy chains) var got_exit bool // Flag to indicate an exit node has been selected var first_byte int // First byte of message slice var last_byte int // Last byte of message slice // Fragments loop begins here for cnum = 1; cnum <= numc; cnum++ { final.setChunkNum(cnum) // First byte of message fragment first_byte = (cnum - 1) * maxFragLength last_byte = first_byte + maxFragLength // Don't slice beyond the end of the message if last_byte > plainLen { last_byte = plainLen } got_exit = false // If no copies flag is specified, use the config file NUMCOPIES if flag_copies == 0 { flag_copies = cfg.Stats.Numcopies } if flag_copies > maxCopies { // Limit copies to a maximum of 10 flag_copies = maxCopies } // Copies loop begins here for n := 0; n < flag_copies; n++ { if got_exit { // Set the last node in the chain to the // previously select exitnode in_chain[len(in_chain)-1] = exitnode } var chain []string chain, err = makeChain(in_chain) if err != nil { Error.Println(err) os.Exit(0) } if len(chain) != len(in_chain) { err = fmt.Errorf( "Chain length mismatch. In=%d, Out=%d", len(in_chain), len(chain)) panic(err) } //fmt.Println(chain) if !got_exit { exitnode = chain[len(chain)-1] got_exit = true } // Retain the entry hop. We need to mail the message to it. sendTo := chain[0] // Report the chain if we're running as a client. if flag_client { fmt.Printf("Chain: %s\n", strings.Join(chain, ",")) } yamnMsg := encodeMsg( plain[first_byte:last_byte], chain, *final, ) writeMessageToPool(sendTo, yamnMsg) } // End of copies loop } // End of fragments loop // Decide if we want to inject a dummy if !flag_nodummy && Pubring.HaveStats() && dice() < 80 { dummy() } }