Syntax: Ruby
Ruby Script #1
#!/usr/bin/env ruby
# Copyright (c) 2009 Samuel Williams. Released under the GNU GPLv3.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
require 'rubygems'
require 'rexec'
require 'rexec/daemon'
require 'rubygems'
require 'rubydns'
# To run this command, use the standard daemon syntax as root
# ./daemon2.rb start
# You should be able to see that the server has dropped priviledges
# # ps aux | grep daemon2.rb
# daemon 16555 0.4 0.0 81392 2024 ?? S 3:35am 0:00.28 ruby ../test/daemon2.rb start
# Test using the following command
# dig @localhost test.mydomain.org
# You might need to change the user name "daemon". This can be a user name or a user id.
RUN_AS = "daemon"
# UDP Socket does per packet reverse lookups unless this is set.
UDPSocket.do_not_reverse_lookup = true
# We need to be root in order to bind to privileged port
if RExec.current_user != "root"
$stderr.puts "Sorry, this command needs to be run as root!"
exit 1
end
# The Daemon itself
class Server < RExec::Daemon::Base
@@var_directory = File.dirname(__FILE__)
def self.run
# Bind to port 53 (UDP)
socket = UDPSocket.new
socket.bind("0.0.0.0", 53)
# Drop priviledges
RExec.change_user(RUN_AS)
# Don't buffer output (for debug purposes)
$stderr.sync = true
# Use upstream DNS for name resolution (These ones are Orcon DNS in NZ)
$R = Resolv::DNS.new(:nameserver => ["60.234.1.1", "60.234.2.2"])
# Start the RubyDNS server
RubyDNS::run_server(:listen => [socket]) do
match("test.mydomain.org", :A) do |transaction|
transaction.respond!("10.0.0.80")
end
# Default DNS handler
otherwise do |transaction|
logger.info "Passthrough: #{transaction}"
transaction.passthrough!($R)
end
end
end
end
# RExec daemon runner
Server.daemonize
Ruby Script #2
#!/usr/bin/env ruby
# Simple Operator Expression Parser
require 'set'
DEBUG = false
class Array
def map_to(with)
r = {}
each_with_index { |v,i| r[v] = with[i] }
return r
end
end
module Expression
class Context
def initialize(operators, values)
@values = values
@operators = operators
end
def value_of (key)
@values[key]
end
def call (op, args)
@operators.call(op, args)
end
end
class Constant
def initialize(value)
@value = value
end
def evaluate (ctx)
return @value
end
end
class Identifier
def initialize(name)
@name = name
end
def evaluate (ctx)
ctx.value_of(@name)
end
end
class Operator
def initialize(name, args = [])
@name = name
@args = args
end
def name
@name
end
def evaluate (ctx)
ctx.call(@name, @args.collect { |a| a.evaluate(ctx) })
end
def args
@args
end
end
class Brackets
def initialize(node)
@node = node
end
def evaluate (ctx)
@node.evaluate(ctx)
end
end
class Parser
def initialize(ops, expr)
@identifiers = []
@operators = ops
# Tokens and expressions line up
@expressions = []
@tokens = []
@top = nil
parse(expr)
end
def evaluate (ctx)
@expressions.collect do |expr|
expr != nil ? expr.evaluate(ctx) : nil
end
end
def identifiers
@identifiers
end
def tokens
@tokens
end
private
def parse(expr)
symbols = @operators.keys + ["(", ")"]
tokenizer = Regexp.union(Regexp.union(*symbols), /[A-Z]+/)
@tokens = expr.scan(tokenizer)
@expressions = [nil] * @tokens.size
@identifiers = Set.new(expr.scan(/[A-Z]+/))
@top, i = process_expression
if DEBUG
puts "Processed #{i} tokens..."
puts "Tokens: " + @tokens.join(" ")
puts @top.inspect
puts @expressions.inspect
end
end
def process_expression(i = 0)
ast = []
ops = {}
while i < @tokens.size
t = @tokens[i]
if t == "("
result, i = process_expression(i+1)
ast += result
elsif t == ")"
break
else
result = process_token(i)
ast << result
end
if result.class == Operator
ops[result.name] ||= []
# Store the index
ops[result.name] << (ast.size - 1)
end
i += 1
end
#puts ast.inspect
# We need to sort the list of operators now
# [c, infix, prefix, c]
@operators.order.each do |name|
op_kind = @operators.kind(name)
next unless ops[name]
ops[name].each do |loc|
op = ast[loc]
if op_kind == :prefix
rhs = find_subexpression(ast, loc, RHS_SEARCH)
op.args << ast[rhs]
ast[rhs] = nil
elsif op_kind == :infix
lhs = find_subexpression(ast, loc, LHS_SEARCH)
rhs = find_subexpression(ast, loc, RHS_SEARCH)
op.args << ast[lhs]
op.args << ast[rhs]
ast[lhs] = ast[rhs] = nil
elsif op_kind == :postfix
lhs = find_subexpression(ast, loc, LHS_SEARCH)
op.args << ast[lhs]
ast[rhs] = nil
end
end
end
return [ast.uniq, i]
end
RHS_SEARCH = 1
LHS_SEARCH = -1
def find_subexpression(ast, loc, dir)
while loc >= 0 && loc < ast.size
loc += dir
return loc if ast[loc] != nil
end
return nil
end
def process_token(i)
t = @tokens[i]
if @operators.key? t
tok = Operator.new(t)
elsif t.match /[A-Z]+/
tok = Identifier.new(t)
else
tok = Constant.new(t)
end
@expressions[i] = tok
return tok
end
end
TYPE = 0
FUNC = 1
class Operators
def initialize
@operators = {}
@order = []
end
def add(sym, kind, &block)
@operators[sym] = [kind, block]
@order << sym
end
def order
@order
end
def keys
@operators.keys
end
def key? k
@operators.key? k
end
def kind k
@operators[k][0]
end
def call(k, args)
@operators[k][1].call(*args)
end
end
end