Time access restrictions [WIP]

Because my daughter spends way too much time on Youtube
Because people have been asking OpenDNS to implement this for the past 10 years
Because existing tools suck
Because I want something flexible, where every rule can be assigned a schedule
This commit is contained in:
Frank Denis 2018-01-31 23:08:38 +01:00
parent ba2293149e
commit 41a73ccb03
5 changed files with 88 additions and 75 deletions

View File

@ -28,3 +28,9 @@ tracker.*
*.local
eth0.me
*.workgroup
## Time-based rules
youtube.* @time-to-sleep

View File

@ -222,9 +222,11 @@ func ConfigLoad(proxy *Proxy, svcFlag *string) error {
proxy.forwardFile = config.ForwardFile
if err := parseAllWeeklyRanges(config.AllWeeklyRanges); err != nil {
allWeeklyRanges, err := ParseAllWeeklyRanges(config.AllWeeklyRanges)
if err != nil {
return err
}
proxy.allWeeklyRanges = allWeeklyRanges
if err := config.loadSources(proxy); err != nil {
return err

View File

@ -318,13 +318,15 @@ format = 'tsv'
## Time access restrictions (WIP)
[time_ranges]
[time_ranges.'timetosleep']
mon = [{after="22:00", before="07:00"}]
tue = [{after="22:00", before="07:00"}]
wed = [{after="22:00", before="07:00"}]
thu = [{after="22:00", before="07:00"}]
fri = [{after="22:00", before="07:00"}]
sat = [{after="22:00", before="07:00"}]
[time_ranges.'time-to-sleep']
mon = [{after="21:00", before="07:00"}]
tue = [{after="21:00", before="07:00"}]
wed = [{after="21:00", before="07:00"}]
thu = [{after="21:00", before="07:00"}]
fri = [{after="23:00", before="07:00"}]
sat = [{after="23:00", before="07:00"}]
sun = [{after="22:00", before="07:00"}]

View File

@ -36,7 +36,7 @@ type PluginBlockName struct {
blockedPatterns []string
outFd *os.File
format string
timeRanges map[string]*WeeklyRanges
allWeeklyRanges *map[string]WeeklyRanges
}
type TimeRange struct {
@ -57,66 +57,6 @@ type WeeklyRangesStr struct {
Sun, Mon, Tue, Wed, Thu, Fri, Sat []TimeRangeStr
}
func daySecsFromStr(str string) (int, error) {
parts := strings.Split(str, ":")
if len(parts) != 2 {
return -1, fmt.Errorf("Syntax error in a time expression: [%s]", str)
}
hours, err := strconv.Atoi(parts[0])
if err != nil || hours < 0 || hours > 23 {
return -1, fmt.Errorf("Syntax error in a time expression: [%s]", str)
}
minutes, err := strconv.Atoi(parts[1])
if err != nil || minutes < 0 || minutes > 59 {
return -1, fmt.Errorf("Syntax error in a time expression: [%s]", str)
}
return (hours*60 + minutes) * 60, nil
}
func parseTimeRanges(timeRangesStr []TimeRangeStr) ([]TimeRange, error) {
timeRanges := []TimeRange{}
for _, timeRangeStr := range timeRangesStr {
after, err := daySecsFromStr(timeRangeStr.After)
if err != nil {
return timeRanges, err
}
before, err := daySecsFromStr(timeRangeStr.Before)
if err != nil {
return timeRanges, err
}
if after == before {
after, before = -1, 86402
}
timeRanges = append(timeRanges, TimeRange{after: after, before: before})
}
return timeRanges, nil
}
func parseWeeklyRanges(weeklyRangesStr WeeklyRangesStr) (WeeklyRanges, error) {
weeklyRanges := WeeklyRanges{}
weeklyRangesStrX := [7][]TimeRangeStr{weeklyRangesStr.Sun, weeklyRangesStr.Mon, weeklyRangesStr.Tue, weeklyRangesStr.Wed, weeklyRangesStr.Thu, weeklyRangesStr.Fri, weeklyRangesStr.Sat}
for day, weeklyRangeStrX := range weeklyRangesStrX {
timeRanges, err := parseTimeRanges(weeklyRangeStrX)
if err != nil {
return weeklyRanges, err
}
weeklyRanges.ranges[day] = timeRanges
}
return weeklyRanges, nil
}
func parseAllWeeklyRanges(allWeeklyRangesStr map[string]WeeklyRangesStr) error {
allWeeklyRanges := make(map[string]WeeklyRanges)
for weeklyRangesName, weeklyRangesStr := range allWeeklyRangesStr {
weeklyRanges, err := parseWeeklyRanges(weeklyRangesStr)
if err != nil {
return err
}
allWeeklyRanges[weeklyRangesName] = weeklyRanges
}
return nil
}
func (plugin *PluginBlockName) Name() string {
return "block_name"
}
@ -131,6 +71,7 @@ func (plugin *PluginBlockName) Init(proxy *Proxy) error {
if err != nil {
return err
}
plugin.allWeeklyRanges = proxy.allWeeklyRanges
plugin.blockedPrefixes = iradix.New()
plugin.blockedSuffixes = iradix.New()
for lineNo, line := range strings.Split(string(bin), "\n") {
@ -182,14 +123,15 @@ func (plugin *PluginBlockName) Init(proxy *Proxy) error {
dlog.Errorf("Syntax error in block rule at line %d", 1+lineNo)
continue
}
var timeRange *TimeRange
var weeklyRanges *WeeklyRanges
if len(timeRangeName) > 0 {
timeRange, ok := plugin.timeRanges[timeRangeName]
weeklyRangesX, ok := (*plugin.allWeeklyRanges)[timeRangeName]
if !ok {
dlog.Errorf("Time range [%s] not found at line %d", timeRangeName, 1+lineNo)
timeRange = nil
} else {
weeklyRanges = &weeklyRangesX
}
_ = timeRange
_ = weeklyRanges
}
line = strings.ToLower(line)
switch blockType {
@ -198,9 +140,9 @@ func (plugin *PluginBlockName) Init(proxy *Proxy) error {
case PluginBlockTypePattern:
plugin.blockedPatterns = append(plugin.blockedPatterns, line)
case PluginBlockTypePrefix:
plugin.blockedPrefixes, _, _ = plugin.blockedPrefixes.Insert([]byte(line), timeRange)
plugin.blockedPrefixes, _, _ = plugin.blockedPrefixes.Insert([]byte(line), weeklyRanges)
case PluginBlockTypeSuffix:
plugin.blockedSuffixes, _, _ = plugin.blockedSuffixes.Insert([]byte(StringReverse(line)), timeRange)
plugin.blockedSuffixes, _, _ = plugin.blockedSuffixes.Insert([]byte(StringReverse(line)), weeklyRanges)
default:
dlog.Fatal("Unexpected block type")
}
@ -319,3 +261,63 @@ func isGlobCandidate(str string) bool {
}
return false
}
func daySecsFromStr(str string) (int, error) {
parts := strings.Split(str, ":")
if len(parts) != 2 {
return -1, fmt.Errorf("Syntax error in a time expression: [%s]", str)
}
hours, err := strconv.Atoi(parts[0])
if err != nil || hours < 0 || hours > 23 {
return -1, fmt.Errorf("Syntax error in a time expression: [%s]", str)
}
minutes, err := strconv.Atoi(parts[1])
if err != nil || minutes < 0 || minutes > 59 {
return -1, fmt.Errorf("Syntax error in a time expression: [%s]", str)
}
return (hours*60 + minutes) * 60, nil
}
func parseTimeRanges(timeRangesStr []TimeRangeStr) ([]TimeRange, error) {
timeRanges := []TimeRange{}
for _, timeRangeStr := range timeRangesStr {
after, err := daySecsFromStr(timeRangeStr.After)
if err != nil {
return timeRanges, err
}
before, err := daySecsFromStr(timeRangeStr.Before)
if err != nil {
return timeRanges, err
}
if after == before {
after, before = -1, 86402
}
timeRanges = append(timeRanges, TimeRange{after: after, before: before})
}
return timeRanges, nil
}
func parseWeeklyRanges(weeklyRangesStr WeeklyRangesStr) (WeeklyRanges, error) {
weeklyRanges := WeeklyRanges{}
weeklyRangesStrX := [7][]TimeRangeStr{weeklyRangesStr.Sun, weeklyRangesStr.Mon, weeklyRangesStr.Tue, weeklyRangesStr.Wed, weeklyRangesStr.Thu, weeklyRangesStr.Fri, weeklyRangesStr.Sat}
for day, weeklyRangeStrX := range weeklyRangesStrX {
timeRanges, err := parseTimeRanges(weeklyRangeStrX)
if err != nil {
return weeklyRanges, err
}
weeklyRanges.ranges[day] = timeRanges
}
return weeklyRanges, nil
}
func ParseAllWeeklyRanges(allWeeklyRangesStr map[string]WeeklyRangesStr) (*map[string]WeeklyRanges, error) {
allWeeklyRanges := make(map[string]WeeklyRanges)
for weeklyRangesName, weeklyRangesStr := range allWeeklyRangesStr {
weeklyRanges, err := parseWeeklyRanges(weeklyRangesStr)
if err != nil {
return nil, err
}
allWeeklyRanges[weeklyRangesName] = weeklyRanges
}
return &allWeeklyRanges, nil
}

View File

@ -47,6 +47,7 @@ type Proxy struct {
clientsCount uint32
maxClients uint32
xTransport *XTransport
allWeeklyRanges *map[string]WeeklyRanges
}
func (proxy *Proxy) StartProxy() {