summaryrefslogtreecommitdiff
path: root/transport/socat.sh
blob: c3655dec207a99da8ffc53ec93150491f0fd48e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#!/bin/bash
# -*- coding: utf-8 -*-
###########################################################################
#                                                                         #
#  envbot - an IRC bot in bash                                            #
#  Copyright (C) 2007-2008  Arvid Norlander                               #
#                                                                         #
#  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/>.  #
#                                                                         #
###########################################################################
#---------------------------------------------------------------------
## A transport module using socat
#---------------------------------------------------------------------

# A list of features supported
# This is set in transport_check_support
transport_check_support=''

# Check if all the stuff needed to use this transport is available
# Return status
#   0 Yes
#   1 No
transport_check_support() {
	hash socat >/dev/null 2>&1 || {
		log_fatal "Can't find socat (needed for this transport)"
		return 1
	}
	hash mkfifo >/dev/null 2>&1 || {
		log_fatal "Can't find mkfifo (needed for this transport)"
		return 1
	}
	# Build transport_supports
	local features="$(socat -V | grep -E 'socat version|define')"
	# These seems to always be supported?
	transport_supports="nossl bind"
	if grep -q WITH_IP4 <<< "$features"; then
		transport_supports+=" ipv4"
	fi
	if grep -q WITH_IP6 <<< "$features"; then
		transport_supports+=" ipv6"
	fi
	if grep -q WITH_OPENSSL <<< "$features"; then
		transport_supports+=" ssl"
	fi
	if [[ -z $config_transport_socat_protocol_family ]]; then
		log_fatal "You need to set config_transport_socat_protocol_family in your config to either ipv4 or ipv6."
		return 1
	fi
	# Check for older version
	if grep -q "socat version 1.4" <<< "$features"; then
		# SSL + IPv6 is not supported with socat-1.4.x
		if [[ $config_server_ssl -ne 0 ]]; then
			# list_remove is not yet loaded so we can't use that here...
			transport_supports="$(sed "s/ipv6//" <<< "$transport_supports")"
		fi
		# This is to be sure socat-1.4.x works
		# Modules should normally never set config_* in them
		# This is an exception.
		if [[ -z $config_transport_socat_protocol_family ]]; then
			config_transport_socat_protocol_family="ipv4"
		fi
		# Remember version to find what workaround to use in transport_connect()
		transport_socat_is_14="1"
	else
		transport_socat_is_14="0"
	fi
	return 0
}

# Try to connect
# Parameters
#   $1 hostname/IP
#   $2 port
#   $3 If 1 use SSL. If the module does not support it, just ignore it.
#   $4 IP to bind to if any and if supported
#      If the module does not support it, just ignore it.
# Return status
#   0 if Ok
#   1 if connection failed
transport_connect() {
	transport_tmp_dir_file="$(mktemp -dt envbot.socat.XXXXXXXXXX)" || return 1
	# To keep this simple, from client perspective.
	# We WRITE to out and READ from in
	mkfifo "${transport_tmp_dir_file}/in"
	mkfifo "${transport_tmp_dir_file}/out"
	exec 3<&-
	exec 4<&-
	local addrargs socatnewargs
	if [[ $3 -eq 1 ]]; then
		addrargs="OPENSSL"
		# HACK: Support IPv6 with SSL if socat is new enough.
		if [[ $transport_socat_is_14 -eq 0 ]]; then
			if [[ $config_transport_socat_protocol_family = "ipv6" ]]; then
				socatnewargs=",pf=ip6"
			elif [[ $config_transport_socat_protocol_family = "ipv4" ]]; then
				socatnewargs=",pf=ip4"
			fi
		fi
	elif [[ $config_transport_socat_protocol_family = "ipv6" ]]; then
		addrargs="TCP6"
	elif [[ $config_transport_socat_protocol_family = "ipv4" ]]; then
		addrargs="TCP4"
	fi
	# Add in hostname and port.
	addrargs+=":${1}:${2}"
	# Should we bind an IP? Then lets do that.
	if [[ $4 ]]; then
		addrargs+=",bind=$4"
	fi
	# If version 1.5 or later add in extra args
	if [[ $transport_socat_is_14 -eq 0 ]]; then
		addrargs+="${socatnewargs}"
	fi
	# If we use SSL check if we should verify.
	if [[ $3 -eq 1 && $config_server_ssl_accept_invalid -eq 1 ]]; then
		addrargs+=",verify=0"
	fi
	socat STDIO "$addrargs" < "${transport_tmp_dir_file}/out" > "${transport_tmp_dir_file}/in" &
	transport_pid="$!"
	echo "$transport_pid" >> "${transport_tmp_dir_file}/pid"
	exec 3>"${transport_tmp_dir_file}/out"
	exec 4<"${transport_tmp_dir_file}/in"
	# To be able to wait for error.
	sleep 2
	kill -0 "$transport_pid" >/dev/null 2>&1 || return 1
	time_get_current 'transport_lastvalidtime'
}

# Called to close connection
# No parameters, no return code check
transport_disconnect() {
	# It might not be running.
	kill "$(< "${transport_tmp_dir_file}/pid")" >/dev/null 2>&1
	rm -rf "${transport_tmp_dir_file}"
	exec 3<&-
	exec 4<&-
	# To force code to consider this disconnected.
	transport_lastvalidtime=0
}

# Return status
#   0 If connection is still alive
#   1 If it isn't.
transport_alive() {
	kill -0 "$transport_pid" >/dev/null 2>&1 || return 1
	local newtime=
	time_get_current 'newtime'
	(( newtime - transport_lastvalidtime > 300 )) && return 1
	return 0
}

# Return a line in the variable line.
# Return status
#   0 If Ok
#   1 If connection failed
transport_read_line() {
    while true
    do
	ze_length="$( wc -l '/tmp/un-provoked-message-store' 2> /dev/null )"

	if [[ -r /tmp/un-provoked-message-store ]] &&
	     [[ -w /tmp/un-provoked-message-store ]] && (( ${ze_length%% *} ))
	then
	    read -r line < /tmp/un-provoked-message-store
	    line=':'${INJECT_NICK}'!~user@2001:ba8:1f1:f216::5 PRIVMSG #parabola :'"${line}"

	    if (( ${ze_length%% *} < 2 ))
	    then
		echo -n > /tmp/un-provoked-message-store
	    else
		tail -n +2 /tmp/un-provoked-message-store |
		sponge /tmp/un-provoked-message-store
	    fi

	    break
	else
	    read -t 5 -ru 4 line
	    the_return_code="${?}"
	    (( the_return_code == 0 )) && break
	    (( the_return_code > 128 )) && continue
	    (( the_return_code -ne 0 )) && return
	fi
    done

    time_get_current 'transport_lastvalidtime'
    line=${line//$'\r'/}
}

# Send a line
# Parameters
#   $* send this
# Return code not checked.
transport_write_line() {
	kill -0 "$transport_pid" >/dev/null 2>&1 && echo "$*" >&3
}