-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge #80: Automatically sync TLSA records with Firefox cert_override…
….txt fade5f4 Allow ncdns to automatically sync TLSA records with Firefox cert_override.txt. (JeremyRand) Pull request description: Tree-SHA512: 05360437bea506eacb71e37d62781627f5c60de61c4b30d60c2e0efa7da9f511a087715514cdc5be0ab0fbcf0229bfea31133dcb486c947a4068d7b562ad13c4
- Loading branch information
Showing
3 changed files
with
191 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package tlsoverridefirefox | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"strings" | ||
) | ||
|
||
// FilterOverrides accepts as input the contents of a Firefox cert_override.txt | ||
// and a host suffix to blacklist (usually "bit"). It returns the contents of | ||
// a new Firefox cert_override.txt that contains all overrides as the input | ||
// file except for those that match the host suffix. | ||
func FilterOverrides(overrides, blacklistedHostSuffix string) (string, error) { | ||
result := "" | ||
|
||
overridesSlice := strings.Split(overrides, "\n") | ||
|
||
for _, override := range overridesSlice { | ||
trimmed := strings.TrimSpace(override) | ||
if trimmed == "" { | ||
// This is a blank line; don't try to parse it or | ||
// include it in output. | ||
continue | ||
} | ||
if strings.HasPrefix(trimmed, "#") { | ||
// This is a comment; pass it through verbatim. | ||
result = result + override + "\n" | ||
continue | ||
} | ||
|
||
tabSplit := strings.Split(override, "\t") | ||
hostAndPort := tabSplit[0] | ||
|
||
host, _, err := net.SplitHostPort(hostAndPort) | ||
if err != nil { | ||
// Don't log err since it may contain private data. | ||
return "", fmt.Errorf("Error parsing hostport") | ||
} | ||
|
||
if host == blacklistedHostSuffix || | ||
strings.HasSuffix(host, "."+blacklistedHostSuffix) { | ||
// Host is blacklisted; don't include it in output | ||
continue | ||
} | ||
|
||
result = result + override + "\n" | ||
} | ||
|
||
return result, nil | ||
} |
134 changes: 134 additions & 0 deletions
134
tlsoverridefirefox/tlsoverridefirefoxsync/firefoxoverridesync.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package tlsoverridefirefoxsync | ||
|
||
import ( | ||
"bytes" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"sync" | ||
"time" | ||
|
||
"github.com/hlandau/xlog" | ||
"gopkg.in/hlandau/easyconfig.v1/cflag" | ||
|
||
"github.com/namecoin/ncdns/namecoin" | ||
"github.com/namecoin/ncdns/ncdumpzone" | ||
"github.com/namecoin/ncdns/tlsoverridefirefox" | ||
) | ||
|
||
var ( | ||
flagGroup = cflag.NewGroup(nil, "tlsoverridefirefox") | ||
syncEnableFlag = cflag.Bool(flagGroup, "sync", false, | ||
"Synchronize TLSA records from the Namecoin zone to Firefox's "+ | ||
"cert_override.txt") | ||
firefoxProfileDirFlag = cflag.String(flagGroup, "profiledir", "", | ||
"Firefox profile directory") | ||
) | ||
|
||
var log, Log = xlog.New("ncdns.tlsoverridefirefoxsync") | ||
|
||
var zoneData string | ||
var zoneDataReady = false | ||
var zoneDataMux sync.Mutex | ||
|
||
// Note: the reason for the Fatal reaction to errors is that, if we stop | ||
// syncing the override list, Firefox will continue trusting .bit certs that | ||
// might be revoked in Namecoin. Therefore, it is important that, in such a | ||
// situation, .bit domains must stop resolving until the issue is corrected. | ||
// Forcing ncdns to exit is the least complex way to achieve this. | ||
|
||
func watchZone(conn namecoin.Conn) { | ||
for { | ||
var result bytes.Buffer | ||
|
||
err := ncdumpzone.Dump(conn, &result, "firefox-override") | ||
log.Fatale(err, "Couldn't dump zone for Firefox override sync") | ||
|
||
zoneDataMux.Lock() | ||
zoneData = result.String() | ||
zoneDataReady = true | ||
zoneDataMux.Unlock() | ||
|
||
time.Sleep(10 * time.Minute) | ||
} | ||
} | ||
|
||
func watchProfile(suffix string) { | ||
if firefoxProfileDirFlag.Value() == "" { | ||
log.Fatal("Missing required config option tlsoverridefirefox.profiledir") | ||
} | ||
|
||
for { | ||
if profileInUse() { | ||
time.Sleep(1 * time.Second) | ||
continue | ||
} | ||
|
||
// At this point we know that Firefox is not running. | ||
|
||
zoneDataMux.Lock() | ||
zoneDataReadyLocal := zoneDataReady | ||
zoneDataLocal := zoneData | ||
zoneDataMux.Unlock() | ||
|
||
if !zoneDataReadyLocal { | ||
time.Sleep(1 * time.Second) | ||
continue | ||
} | ||
|
||
log.Debug("Syncing zone to cert_override.txt...") | ||
|
||
prevOverrides, err := ioutil.ReadFile( | ||
firefoxProfileDirFlag.Value() + "/cert_override.txt") | ||
if err != nil { | ||
if os.IsNotExist(err) { | ||
// cert_override.txt doesn't exist in a default | ||
// Firefox install; it's only created once the | ||
// first override is configured in the Firefox | ||
// GUI. If it's not there, we can pretend we | ||
// read an empty file. | ||
prevOverrides = []byte(``) | ||
} else { | ||
log.Fatale(err, | ||
"Couldn't read Firefox "+ | ||
"cert_override.txt") | ||
} | ||
} | ||
|
||
filteredPrevOverrides, err := tlsoverridefirefox. | ||
FilterOverrides(string(prevOverrides), suffix) | ||
log.Fatale(err, "Couldn't filter Firefox overrides") | ||
|
||
newOverrides := filteredPrevOverrides + zoneDataLocal + "\n" | ||
|
||
// TODO: Does 0600 match the default behavior of Firefox? | ||
// TODO: maybe instead write to a temp file and then move the file into place? | ||
err = ioutil.WriteFile(firefoxProfileDirFlag.Value()+ | ||
"/cert_override.txt", []byte(newOverrides), 0600) | ||
log.Fatale(err, "Couldn't write Firefox cert_override.txt") | ||
|
||
log.Debug("Finished syncing zone to cert_override.txt") | ||
|
||
time.Sleep(10 * time.Minute) | ||
} | ||
} | ||
|
||
func profileInUse() bool { | ||
// This glob pattern matches the ".sqlite-wal" and ".sqlite-shm" files | ||
// that are only present when Firefox's databases are open. | ||
matches, err := filepath.Glob(firefoxProfileDirFlag.Value() + "/*.sqlite-*") | ||
log.Fatale(err, "Couldn't check if Firefox is running for override sync") | ||
|
||
return matches != nil | ||
} | ||
|
||
// Start starts 2 background threads that synchronize the blockchain's TLSA | ||
// records to a Firefox profile's cert_override.txt. It accepts a connection | ||
// to access Namecoin Core, as well as a host suffix (usually "bit"). | ||
func Start(conn namecoin.Conn, suffix string) error { | ||
if syncEnableFlag.Value() { | ||
go watchZone(conn) | ||
go watchProfile(suffix) | ||
} | ||
return nil | ||
} |