:::::::::::::: /etc/sendmail-cfg.rb :::::::::::::: SMTPHELO = 'hostname.domain' FROM = 'user@domain' :::::::::::::: /usr/lib/sendmail :::::::::::::: #!/usr/bin/ruby require 'resolv' require 'net/smtp' require '/etc/sendmail-cfg' $VERBOSE = false class Xref def initialize @hash = {} end def assoc key, val @hash[key] = [] if @hash[key].nil? @hash[key] << val end def ref key @hash[key] end def each for key, val in @hash yield key, val end end end text = [] for line in $stdin break if /^\.\r?$/ === line text.push line end text.unshift "From: #{FROM}\r\n" if text.grep(/^From:/i).empty? text = text.join dns = Resolv::DNS::new IN = Resolv::DNS::Resource::IN distri = Xref.new p ARGV if $VERBOSE for recip in ARGV hostpart = recip.sub(/^.*@/, '') mx = dns.getresources(host = hostpart, IN::MX) unless mx.empty? distri.assoc mx.first.exchange.to_s, recip next end distri.assoc hostpart, recip end p distri if $VERBOSE for serv, recips in distri p [serv, recips] if $VERBOSE Net::SMTP.start(serv, 25, SMTPHELO) { |smtp| smtp.send_mail text, FROM, *recips } end :::::::::::::: /usr/local/bin/host :::::::::::::: #!/usr/bin/ruby require 'optparse' require 'resolv' def barf message $stderr.puts message end type = 'A' opt = OptionParser.new opt.on('-t type', 'specifies the query type') { |arg| type = arg } opt.on('-v', 'more verbose') { $VERBOSE = true } opt.on('-d', 'is equivalent to -v') { $VERBOSE = true } opt.on('-a', 'equivalent to -v -t *') { $VERBOSE = true; type = '*' } opt.parse!(ARGV) if ARGV.empty? print opt.to_s exit 1 end type = 'any' if type == '*' IN = Resolv::DNS::Resource::IN type = IN.const_get(type.upcase) for resource in Resolv::DNS::new.getresources(host = ARGV.first, type) case resource when IN::NS puts "#{host} name server #{resource.name}" when IN::CNAME puts "#{host} is an alias for #{resource.name}" when IN::MX puts "#{host} is handled by #{resource.preference} #{resource.exchange}" when IN::A puts resource.address else puts resource.to_s end end :::::::::::::: /usr/local/bin/mail :::::::::::::: #!/usr/bin/ruby require 'optparse' Headers = Struct.new(:subject, :from, :to, :cc) hdrs = Headers.new(nil, nil, [], []) recips = Hash.new def barf message $stderr.puts message exit 16 end opt = OptionParser.new opt.on('-s subject') { |arg| hdrs.subject = arg } opt.on('-c cc-addrs') { |list| list.split(/,\s*/).each { |addr| hdrs.cc << addr recips[addr] = true }} opt.on('-f') { barf 'fake mail: sending only' } opt.on('-u') { barf 'fake mail: sending only' } opt.on('-N') { barf 'fake mail: sending only' } opt.parse!(ARGV) ARGV.each do |addr| hdrs.to << addr recips[addr] = true end if (hdrs.to + hdrs.cc).empty? barf 'at least one recipient required (because I am sending-only fake)' end rcps = (hdrs.to + hdrs.cc).collect { |addr| addr.sub(/[^-.@A-Z_a-z]/, '') } if hdrs.subject.nil? and $stdin.tty? $stderr.print 'Subject: ' hdrs.subject = $stdin.readline.strip end p = open("|/usr/lib/sendmail #{rcps.join(' ')}", 'w') p.print "Subject: #{hdrs.subject}\r\n" p.print "To: #{hdrs.to}\r\n" unless hdrs.to.empty? p.print "Cc: #{hdrs.cc}\r\n" unless hdrs.cc.empty? p.print "From: #{hdrs.from}\r\n" if hdrs.from p.print "\r\n" while line = $stdin.gets break if /^\.\s*$/ =~ line p.print line end p.close exit($?.to_i >> 8)