-
Notifications
You must be signed in to change notification settings - Fork 0
/
ftp.sh
executable file
·158 lines (134 loc) · 4.12 KB
/
ftp.sh
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
#! /bin/sh
# source: ftp.sh
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# example how to write a shell script that communicates with stdio on the front
# end and with a socat address on the back end
# usage:
# ftp.sh [opts] server directory/ # show directory contents on stdout
# ftp.sh [opts] server file # print file contents to stdout
# opts:
# -socks socksserver # use given socks server, port 1080
# -proxy proxyserver # use given proxy server, port 8080
# # must be http proxy that accepts CONNECT
# # method to ports 21 and >=1024
# -user username # default: "ftp"
# -passwd password # default: "[email protected]"
# -t # shell script trace+debug
# -d # debug on control connection (use up to 4 times)
# -D # debug on data connection (use up to 4 times)
# -b # block size for data connection
# -v # verbose
# -l* # socat logging options
# example:
# ftp.sh -v -d -d -D -D -D -b 65536 -proxy proxy ftp.ftp.org /README >README
user="ftp"
passwd="[email protected]"
#method="socks4:socks" # socks4 is address spec, socks is socks server name
method=tcp
addropts=
# socat options
SO1=
SO2=
while :; do
case "$1" in
-socks|-socks4) shift;
case "$1" in
*:*) method="socks4:${1%%:*}"; addropts="socksport=${1#*:}" ;;
*) method="socks4:$1" ;;
esac ;;
-socks4a) shift;
case "$1" in
*:*) method="socks4a:${1%%:*}"; addropts="socksport=${1#*:}" ;;
*) method="socks4a:$1" ;;
esac ;;
-proxy) shift;
case "$1" in
*:*) method="proxy:${1%%:*}"; addropts="proxyport=${1#*:}" ;;
*) method="proxy:$1" ;;
esac ;;
-user) shift; user="$1" ;;
-passwd) shift; passwd="$1" ;;
-t) set -vx ;;
-d) SO1="$SO1 -d" ;;
-D) SO2="$SO2 -d" ;;
-b) SO2="$SO2 -b $2"; shift ;;
-v) SO1="$SO1 -v" ;;
-l*) SO1="$SO1 $1"; SO2="$SO2 $1" ;;
-*) echo "unknown option \"$1\"" >&2; exit 1;;
*) break ;;
esac
shift
done
export SO2
server="$1"
dir="$2"
echo "addr=$method:$server:21,$addropts"; exit
### this is the central part to establish communication with socat ###
### copy these lines to make new communication shell scripts
TMPDIR=$(if [ -x /bin/mktemp ]; then
/bin/mktemp -d /tmp/$USER/FTPSH.XXXXXX
else
(umask 077; d=/tmp/$USER/FTPSH.$$; mkdir $d; echo $d)
fi)
TO="$TMPDIR/to"; FROM="$TMPDIR/from"
socat $SO1 fifo:$TO,nonblock,ignoreeof!!fifo:$FROM $method:$server:21,$addropts &
S1=$!
while ! [ -p "$TO" -a -p "$FROM" ]; do sleep 1; done
exec 4>$TMPDIR/to 3<$TMPDIR/from
trap "S1=" 17
#trap "echo cleaning up...>&2; rm -r $TMPDIR; [ -n "$S1" ] && kill $S1" 0 3
trap "rm -r $TMPDIR" 0 3
### here the central part ends
# this function waits for a complete server message, checks if its status
# is in the permitted range (terminates session if not), and returns.
ftp_chat () {
local cmd="$1"
local errlevel="$2"; [ -z "$errlevel" ] && errlevel=300
if [ -n "$cmd" ]; then echo "$cmd" >&4; fi
while read status message <&3;
( case "$status" in [0-9][0-9][0-9]-*) exit 0;; [0-9][0-9][0-9]*) exit 1;; *) exit 1;; esac )
do :; done
#echo "got \"$status $message\"" >&2
if [ -z "$status" ]; then echo ftp data connection failed >&2; exit; fi
if [ "$status" -ge "$errlevel" ]; then
echo $message >&2
echo "QUIT" >&4; exit 1
fi
set +vx
}
# wait for server greeting
ftp_chat
ftp_chat "USER $user" 400
ftp_chat "PASS $passwd"
#ftp_chat "CWD $dir"
case "$dir" in
*/) ftp_chat "TYPE A" ;;
*) ftp_chat "TYPE I" ;;
esac
echo "PASV" >&4; read status message <&3
info=$(expr "$message" : '.*[^0-9]\([0-9]*,[0-9]*,[0-9]*,[0-9]*,[0-9]*,[0-9]*\).*')
echo $info |tr ',' ' ' |(read i1 i2 i3 i4 p1 p2
addr=$i1.$i2.$i3.$i4
port=$(echo "256*$p1+$p2" |bc)
#echo $addr:$port
trap : 20
# open data connection and transfer data
socat -u $SO2 $method:$server:$port,$addropts -
) &
S2=$!
case "$dir" in
*/) ftp_chat "NLST $dir" ;;
#*/) ftp_chat "LIST $dir" ;;
*) ftp_chat "RETR $dir" ;;
esac
case "$status" in
[45]*) kill $S2;;
esac
#echo "waiting for process $S2 to terminate" >&2
wait $S2
ftp_chat
ftp_chat "QUIT"
#echo "waiting for process $S1 to terminate" >&2
wait $S1
exit