[Raw Msg Headers][Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Envelove rewrite? how?




Hi,

I have for sometime been sucessfully using zmailer on my system(s) to route
SMTP traffic on the amateur radio packet network (dont worry too much
about the detail, its really just internet at slower speeds for hosts in the
.ampr.org domain).  Recently my Internet access provider announced it will
be stopping the relaying of SMTP for non-customers addresses (to quite
rightly curb unwanted email).  This I believe is being implemented
soon/tested.

My system(s) spend 100% of their time in the domain g7led.ampr.org, one of
my systems spends some of its time hooked up to my internet provider handling
my (local channel) internet email.  This has been working fairly sucessfully
for a little while, I simply take all email in the .ampr.org domain and put
it in the 'smtp' channel and anything else in the 'iap_inet' channel
(which transports it with SMTP to my internet providers smarthost system).
I also rewrite the From: line of mail going to my internet provider to make
it come from @g7led.demon.co.uk.  But the SMTP envelope (MAIL From:<> line
still reads @odin.g7led.ampr.org> is there anyway I can rewrite this too?

There is also one other translation the iap_inet channel goes under, that is
if I send mail to particular addresses it will replace the From: with
another address (this is set in a table in $MAILVAR/db)

I don't really like dumping files and (complex, to me!) problems on
people and saying I can't do X, but...  My modifications to the stock
crossbar.cf have comment lines with my name around them (this helps me
upgrade!)  so I hope its easy (to those who fully understand every
line of the file) to see what I've done.

Or at could anyone point me to a manual to read?

Darryl

--- /var/lib/zmailer/cf/crossbar.cf ---
provide crossbar

# The crossbar function makes the policy decisions of how the instance of
# a message between a particular sender and recipient should be treated.
# The 'from' and 'to' parameters are quads, i.e., in the form
#
#	(channel host user attributes)
#
# The function may modify any of these elements of both the from and to
# addresses, and must select a message header address rewriting function
# to be applied to this message instance.  If the return value is nil or
# empty, the instance is completely ignored, to the point that if there are
# no other recipients specified a complaint will be generated saying there
# are *no* recipients specified.

# vvvvv Darryl Miles vvvvv
relation -t unordered -f $MAILVAR/db/iap_inet_translate iap_inet_translate
# ^^^^^ Darryl Miles ^^^^^

crossbar (from, to) {
	local rewrite destination tmp

# vvvvv Darryl Miles vvvvv
echo "crossbar from = $(channel $from) $(host $from) $(user $from) $(attributes $from)" >>/tmp/crossbar.dbg
echo "crossbar   to = $(channel $to) $(host $to) $(user $to) $(attributes $to)" >>/tmp/crossbar.dbg
# ^^^^^ Darryl Miles ^^^^^

	# Count them..  (at process.cf !)
	# (we could use this as an ultimate duplicate remover too..)
	db add recipients "$(user $to)" "$(user $from)"

	# Intercept (drop, redirect, bounce, save) the message

	tmp=$(intercept "$(user $from)") &&
		case "$(car $tmp)" in
		# dropping error types for from addresses is necessary to
		# avoid mail loops
		drop|error)
			return ;;
		file)	LOGMSG="$LOGMSG $(car $(cdr $tmp))" ;;
		esac

	# Only intercept mail that is not from the local postmaster,
	# so that error messages can find their way back.

	[ "$(channel $from)" = local -a "$(user $from)" = postmaster ] ||
	tmp=$(intercept "$(user $to)") &&
		case "$(car $tmp)" in
		drop)	return ;;
		error)	setf $(channel $to) error
			setf $(host $to) $(car $(cdr $tmp))
			;;
		file)	LOGMSG="$LOGMSG $(car $(cdr $tmp))" ;;
		esac

	# If we do any alias expansion from the crossbar, we should do this:
	#db flush expansions

	# Determine which rewrite function (for message header addresses) to use

	case $(channel $to) in
	smtp|smtpx)
		#case "$(channel $from)" in
		#smtp|smtpx)	# Address should be forwarded the way the arrive
		#	rewrite=null ;;
		#*)	rewrite=internet ;;
		#esac
		rewrite=internet
		;;
	# vvvvv Darryl Miles vvvvv
	iap_inet)	case "$(channel $from)" in
		iap_inet)	# Address should be forwarded the way the arrive
				rewrite=null ;;
		local)		# Coming from local
#echo "crossbar setting host to $IAPHOSTNAME" >> /tmp/crossbar.dbg
#				setf "$(user $from)" "yyy.$(user $from)@$IAPHOSTNAME"
				rewrite=iap_internet ;;
		*)		rewrite=iap_internet ;;
		esac
		;;
	# ^^^^^ Darryl Miles ^^^^^
	error)	rewrite=null ;;
	local)	case "$(channel $from)" in
		local)	#rewrite=intramachine
			rewrite=internet ;;
		*)	# addresses should be saved the way they arrive
			rewrite=null ;;
		esac
		;;
	usenet)	rewrite=internet ;;
	ean)	rewrite=ean_useratdomain ;;
	*)	# This is usually UUCP or BITNET
		# We want to determine the final destination host/domain
		destination="$(uucproute "$(user $to)")"
		if [ "$(host $to)" ]; then
			destination="$(host $to)"!"$destination"
		fi
		sift "$destination" in
		.*!([^!]+)![^!]+
			destination="\1" ;;	# destination domain
		.*\.(bitnet|netnorth|earn|cdn)
			rewrite=smtp_useratdomain
			break ;;			# reply to user@domain
		.*	rewrite=internet ; break ;;	# default sensible thing
		tfis
		;;
	esac

	# The alias expansion might want to modify the envelope sender
	# of the message instance.  Here we cooperate in the scheme which
	# is to set the 'sender' attribute of the destination address.

	tmp="$(get $(attributes $to) sender)" && [ x"$tmp" != x ] &&
		from=(local "$tmp" "$tmp" $(attributes $from))


	case "$(channel $from)" in
	defrt1*)
		setf "$(user $from)" "$(bitnetroute "$(user $from)")"
		if [ $rewrite = internet ]; then
			rewrite=bitnet2internet
		fi
		;;
	esac

	# Rewrite the envelope addresses appropriately

	case "$(channel $to)" in
#	uucp|local)
	uucp)
		# Local destination on a system that delivers in UCB Mail
		# compatible mail spool files means that the From_ line
		# must be in all-! form, which is the same as the UUCP
		# transport requirement.

		setf "$(user $from)" "$(uucproute "$(user $from)")"
		setf "$(user $to)" "$(uucproute "$(user $to)")"
		sift "$(user $to)" in
		(.)!(.*)	if [ \1 = $(host $to) ]; then
					setf "$(user $to)" \2
				fi
				;;
		tfis
		sift "$(user $to)" in
		(.)\.uucp!(.*)	setf "$(user $to)" \1!\2 ;;
		tfis
		;;
#	smtp)
	smtp|smtpx|local|bsmtp3*)
		tmp="$(smtproute "$(user $from)")"
		sift "$tmp" in
		(@$hostname[:,].*)|([^@:,]+@$hostname)
			break ;;
		.*
			# tmp="@$hostname:$tmp"  # <-- that creates RFC-822
						 #     source-routing, AVOID!
			tmp="$tmp"
			;;
		@(.+):(.+:.+)
			tmp="@\1,\2" ; continue ;;
		tfis
		setf "$(user $from)" "$tmp"
		sift "$(user $to)" in
		(^/).*	setf "$(user $to)" "$(smtproute "$(user $to)")" ;;
		tfis

		;;
	# vvvvv Darryl Miles vvvvv
	iap_inet)
echo "crossbar iap_inet from = $(channel $from) $(host $from) $(user $from) $(attributes $from)" >>/tmp/crossbar.dbg
echo "crossbar iap_inet   to = $(channel $to) $(host $to) $(user $to) $(attributes $to)" >>/tmp/crossbar.dbg
		tmp="$(smtproute "$(user $from)")"
echo "crossbar tmp = $tmp" >>/tmp/crossbar.dbg
		sift "$tmp" in
		(@$hostname[:,].*)|([^@:,]+@$hostname)
			break ;;
		.*
			# tmp="@$hostname:$tmp"  # <-- that creates RFC-822
						 #     source-routing, AVOID!
#			tmp="$tmp"
			tmp="$(user $from)@$IAPHOSTNAME"
			;;
		@(.+):(.+:.+)
			tmp="@\1,\2" ; continue ;;
		tfis
echo "crossbar iap_inet middle from = $(channel $from) $(host $from) $(user $from) $(attributes $from)" >>/tmp/crossbar.dbg
echo "crossbar iap_inet middle  to = $(channel $to) $(host $to) $(user $to) $(attributes $to)" >>/tmp/crossbar.dbg
echo "data: $(iap_inet_translate $(user $to))" >>/tmp/crossbar.dbg
		sift "$(iap_inet_translate $(user $to))" in
		^$	# This don't match nothing, Wargh!
echo "No entry in iap_inet_translate" >>/tmp/crossbar.dbg
			break ;;
		(.+)	#
echo "Entry in iap_inet_translate '$tmp' to '\1'" >>/tmp/crossbar.dbg
			# WoW this is clever, we can even force the real users reply addr :-)
			# zmailer is good.
#			db add header "Reply-To" "$tmp"
#			db add header "Foobar" "$tmp"
#			db add header "FoobarW:" "$tmp"
			tmp="\1"
			break ;;
		tfis
		# From from addr if it's too
echo "crossbar iap_inet middle from = $(channel $from) $(host $from) $(user $from) $(attributes $from)" >>/tmp/crossbar.dbg
echo "crossbar iap_inet middle  to = $(channel $to) $(host $to) $(user $to) $(attributes $to)" >>/tmp/crossbar.dbg
		setf "$(user $from)" "$tmp"
		sift "$(user $to)" in
		(^/).*	setf "$(user $to)" "$(smtproute "$(user $to)")" ;;
		tfis
echo "crossbar iap_inet done from = $(channel $from) $(host $from) $(user $from) $(attributes $from)" >>/tmp/crossbar.dbg
echo "crossbar iap_inet done  to = $(channel $to) $(host $to) $(user $to) $(attributes $to)" >>/tmp/crossbar.dbg

		;;
	# ^^^^^ Darryl Miles ^^^^^
	ean)	
		setf $(user $from) "$(ean_useratdomain "$(user $from)")"
		setf "$(user $to)" "$(ean_useratdomain "$(user $to)")"
		;;
	usenet)
		setf $(user $from) "$(uucproute "$(user $from)")"
		sift $(user $from) in
		$hostname!.*	;;
		.*	setf $(user $from) $hostname!$(user $from) ;;
		tfis
		# newsgroup name only
		setf "$(user $to)" $(localpart "$(user $to)")
		;;
#	bsmtp3|bsmtp3nd)
#		setf $(user $from) "$(bitnetroute "$(user $from)")"
#		tmp="$(bitnetroute "$(user $to)")"
#		sift "$tmp" in
#		.*@([^.]).uucp
#			tmp="$(bitnetShortroute "$(user $to)")" ;;
#		tfis
#		setf "$(user $to)" "$tmp"
#		rewrite=bitnetShortroute
#		;;
	defrt1)
		setf $(user $from) "$(bitnetroute "$(user $from)")"
		setf $(user $to) "$(bitnetroute "$(user $to)")"
		rewrite=bitnetroute
		sift "$(user $to)" in
		(.*)[!%](.+)@(.*)
			to=(error bitnetgw "\3" $(attributes $to))
			rewrite=null
			;;
		tfis
		;;
	esac

	#log recipient: "$(channel $to)" "$(host $to)" "$(user $to)"

	return ($rewrite $from $to)

}	# end of crossbar

# If you want to intercept specific mail messages, this function and the
# associated code in the crossbar and process functions will let you do it.  
# There are three possible actions:
#
#	drop		- completely ignore this address
#	error		- return the specified error message
#	file		- append the message file to the specified file
#
# Both the file and error actions require an argument, which necessitates
# the use of multiple-value return (i.e., return a list) in all cases.
#
# If you don't want to intercept anything, this function should return failure.
# The stub defined here is the usual case, you can override it in the host-
# specific cf file.

intercept (address) {
#	case "$(smtp_useratdomain "$address")" in
#	*@pdq*)		return (file /var/scr/pdq) ;;
#	rayan@csri.*)	return (drop) ;;
#	bitftp*@*)	return (error bounce) ;;
#	esac

	return 1
}

# On mail from one local user to another, we don't want to see all the
# long domain name extensions.  This *can* cause problems with silly UAs,
# if it does you can just redefine 'intramachine' to call 'null' in your
# site or host-specific configuration files.

#
# These rewriters can find out if the address they are processing
# is of sender, or recipient type by executing following functions:
#	$(sender)    && { ... sender only things    ; }
#	$(recipient) && { ... recipient only things ; }
#


intramachine (address, hname) {		# strip hostname if it came from here
	# 'address' is the address we are rewriting
	# 'hname'   is the header whose address(es) we are rewriting;
	#           value here is usually: 'From', 'To', etc.

	sift "$address" in
	(.*)@($hostname|$mydomain)
		address="$(condquote "\1")" ;;
	tfis
	return "$address"
}	# end of intramachine


null (address, hname) {
	# 'address' is the address we are rewriting
	# 'hname'   is the header whose address(es) we are rewriting;
	#           value here is usually: 'From', 'To', etc.

	return "$address"		# surprise!
}

# This is usually the default message-header address rewriting function.
# It is responsible for hostname hiding and qualification.

internet (address, hname) {
	# 'address' is the address we are rewriting
	# 'hname'   is the header whose address(es) we are rewriting;
	#           value here is usually: 'From', 'To', etc.

#	# Alexis Yushin <alexis@NL.net> mentioned that he does following:
#	$(sender) && {
#		local tmp
#		tmp=$(masquerades $address) && address=$tmp
#	}

	address="$(canonicalize "$address")"	# Canonicalize does local
						# hostname hiding...
	sift "$address" in
	(.*)<@(.+)>(.*)
			#if [ $(deliver \2) ]; then	# hostname hiding
			#	address="\1@${mydomain}\3"
			#	break
			#fi
			address="\1@\2\3" # No hostname hiding...
			;;
	(.*)<(.+)>(.*)	address="\1\2\3" ;;		# defocus
	[^@]+		
		# This is a local part address w/o any domains!
		address="$(condquote "$address")"
		address="$address@$mydomain"	# add our hostname
		;;
	tfis

	return "$address"
}	# end of internet

# vvvvv Darryl Miles vvvvv
iap_internet (address) {
	address="$(canonicalize "$address")"	# Canonicalize does local
						# hostname hiding...
echo "crossbar:iap_internet = $address" >>/tmp/crossbar.dbg

	sift "$address" in
	(.*)<@(.+)>(.*)
			#if [ $(deliver \2) ]; then	# hostname hiding
			#	address="\1@${mydomain}\3"
			#	break
			#fi
			address="\1@\2\3" # No hostname hiding...
			;;
	(.*)<(.+)>(.*)	address="\1\2\3" ;;		# defocus
	[^@]+		address="$address@$IAPHOSTNAME" ;;	# add our hostname
	tfis
echo "crossbar:iap_internet into = $address" >>/tmp/crossbar.dbg
	return "$address"
}	# end of internet
# ^^^^^ Darryl Miles ^^^^^
--- END OF FILE ---

-- 
Darryl Miles