提交 d1855cc7 编写于 作者: G Geoff Thorpe

This is a demo that performs SSL tunneling (client and/or server) and is

built using an abstracted state machine with a non-blocking IP wrapper
around it. README will follow in the next commit.
上级 14c6d27d
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=NZ, L=Wellington, O=Really Irresponsible Authorisation Authority (RIAA), OU=Cert-stamping, CN=Jackov al-Trades/Email=none@fake.domain
Validity
Not Before: Nov 1 21:09:30 2000 GMT
Not After : Nov 1 21:09:30 2001 GMT
Subject: C=NZ, L=Auckland, O=Silly City-Boys Corp., OU=Internal counselling, CN=tunala-client/Email=client@fake.domain
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:a5:b2:8e:de:05:d1:fe:29:f7:46:a6:6b:a0:e5:
41:2c:f7:55:a8:53:5a:e8:37:1a:68:29:5d:fd:7e:
a4:40:b5:ce:e0:44:54:9e:c6:f8:9a:40:bb:45:41:
57:cc:dc:97:d9:66:3e:68:9d:29:93:15:f9:2b:75:
aa:49:7f:e6:cf:7f:95:44:8e:41:ed:05:97:1e:cb:
3f:03:33:b0:21:2b:89:67:08:cc:7b:b2:ef:fa:26:
c7:ea:21:f2:77:5f:bd:e2:67:36:0a:e2:3d:ee:76:
4f:d2:d3:e9:bb:22:c0:bb:0c:e4:a2:8c:aa:71:3b:
75:6c:46:a7:d2:1b:57:ee:f3
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
74:A8:8B:1F:5B:59:55:09:CB:98:5C:2F:41:87:CA:AC:D4:B5:04:FF
X509v3 Authority Key Identifier:
keyid:57:5A:5D:E0:71:0B:0C:E0:0F:51:87:DE:08:C8:25:E7:F7:87:46:C0
DirName:/C=NZ/L=Wellington/O=Really Irresponsible Authorisation Authority (RIAA)/OU=Cert-stamping/CN=Jackov al-Trades/Email=none@fake.domain
serial:00
Signature Algorithm: md5WithRSAEncryption
5f:36:74:77:1d:c7:56:71:d3:32:30:12:8f:4d:8e:25:90:1c:
b3:2e:e0:c1:77:75:ea:2c:aa:ef:82:c8:e0:86:8c:df:dc:e1:
86:68:81:91:1e:4e:56:b1:5d:93:6f:80:10:80:c3:d8:c4:3b:
0f:20:dd:43:b5:f8:09:a4:bb:a9:04:11:e0:d4:f9:d9:83:19:
2a:da:7c:bb:4c:c2:4f:57:43:0d:1a:1e:31:61:fb:24:62:92:
74:12:9c:51:ef:12:3e:23:e4:45:66:2b:ac:00:60:bf:a0:ff:
43:da:95:c3:cf:64:40:d2:97:8d:c1:dd:26:ce:5f:b9:a1:ea:
92:32
-----BEGIN CERTIFICATE-----
MIIECDCCA3GgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox
EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp
YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy
dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3
DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMDExMDEyMTA5MzBaFw0wMTExMDEy
MTA5MzBaMIGaMQswCQYDVQQGEwJOWjERMA8GA1UEBxMIQXVja2xhbmQxHjAcBgNV
BAoTFVNpbGx5IENpdHktQm95cyBDb3JwLjEdMBsGA1UECxMUSW50ZXJuYWwgY291
bnNlbGxpbmcxFjAUBgNVBAMTDXR1bmFsYS1jbGllbnQxITAfBgkqhkiG9w0BCQEW
EmNsaWVudEBmYWtlLmRvbWFpbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
pbKO3gXR/in3RqZroOVBLPdVqFNa6DcaaCld/X6kQLXO4ERUnsb4mkC7RUFXzNyX
2WY+aJ0pkxX5K3WqSX/mz3+VRI5B7QWXHss/AzOwISuJZwjMe7Lv+ibH6iHyd1+9
4mc2CuI97nZP0tPpuyLAuwzkooyqcTt1bEan0htX7vMCAwEAAaOCAUAwggE8MAkG
A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp
ZmljYXRlMB0GA1UdDgQWBBR0qIsfW1lVCcuYXC9Bh8qs1LUE/zCB4QYDVR0jBIHZ
MIHWgBRXWl3gcQsM4A9Rh94IyCXn94dGwKGBuqSBtzCBtDELMAkGA1UEBhMCTlox
EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp
YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy
dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3
DQEJARYQbm9uZUBmYWtlLmRvbWFpboIBADANBgkqhkiG9w0BAQQFAAOBgQBfNnR3
HcdWcdMyMBKPTY4lkByzLuDBd3XqLKrvgsjghozf3OGGaIGRHk5WsV2Tb4AQgMPY
xDsPIN1DtfgJpLupBBHg1PnZgxkq2ny7TMJPV0MNGh4xYfskYpJ0EpxR7xI+I+RF
ZiusAGC/oP9D2pXDz2RA0peNwd0mzl+5oeqSMg==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQClso7eBdH+KfdGpmug5UEs91WoU1roNxpoKV39fqRAtc7gRFSe
xviaQLtFQVfM3JfZZj5onSmTFfkrdapJf+bPf5VEjkHtBZceyz8DM7AhK4lnCMx7
su/6JsfqIfJ3X73iZzYK4j3udk/S0+m7IsC7DOSijKpxO3VsRqfSG1fu8wIDAQAB
AoGAUWBCHfQJz6NYl8//p8MvoR/PZ52YVddKFsHKMUbS8BzZ/vZQALKDQW5tCnQu
5KOpx9EY8VPOKThvaNKe0P4Joi+ozOm9UHABAQAL/dzk6NP4NG/GYoBdYDhRowbo
3mdxgbJ95INznK3WhGZNGnhd4umz0P67U2xyc5PklKqCGuECQQDcZQE0ZTi1hQ7Z
hStH5h0soyz9VQrx9wF5nfC64lKbh0f6k/pRJqanJ9EDE9od1tuxyWi0IGhOWGC0
LPeB3S+LAkEAwHdptzi+c4hsGqoAEIuYvXah02LOYS2nCpcOssy3jwj8u6IWqiDf
KGt8J3S5u1afRIca9wgJiFME754FYdQrOQJACerNnBL1800Sdv1EDk8vfuO00Y1z
GaI4wcU2oOIwP2ld9suT1vT7SMhE4nORPAiACEb83CYdK3FUoKbpWEGgswJAe8aP
+yAIAz7x3vgDUKCmGvqHOe2qMf7tFTduYXicd+Vcu8KS9thrC5CMaMd9hsg/Zw/I
PKQzlTNm0j760R5kqQJAeO239gMrscKDFvsqSYr3UKf7uJxCetikhVZE1LH//WiM
Rl5jhu6fL9FgNWuyM0z8VTIgZAX6RwZdn1fb3mFYjw==
-----END RSA PRIVATE KEY-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=NZ, L=Wellington, O=Really Irresponsible Authorisation Authority (RIAA), OU=Cert-stamping, CN=Jackov al-Trades/Email=none@fake.domain
Validity
Not Before: Nov 1 21:14:03 2000 GMT
Not After : Nov 1 21:14:03 2001 GMT
Subject: C=NZ, L=Wellington, O=The Stuff of Culture and Taste, OU=SSL dev things, CN=tunala-server/Email=server@fake.domain
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:a7:07:a0:70:5e:76:4e:98:46:70:0e:53:e3:09:
f4:18:7b:c2:7e:8a:d9:3c:12:52:24:9f:bf:76:e1:
0e:ca:99:c0:ed:fb:0f:7c:d1:1a:6d:9c:1f:e0:19:
3a:65:a4:00:26:19:5b:5f:0e:6d:a2:b0:49:0c:28:
40:c5:43:94:55:57:50:d4:28:8a:35:3c:73:f3:bb:
5a:14:1f:ac:85:ba:b1:20:26:98:9a:92:94:96:fb:
90:1d:c4:18:04:f5:7e:f1:21:d7:34:5c:6e:14:b6:
9b:48:ac:85:c0:50:d9:cf:79:67:a8:9e:3f:80:6c:
ff:68:95:4c:52:95:c9:23:41
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
9F:91:73:D0:8D:11:13:25:8B:68:2A:40:57:8D:96:B7:62:0B:6E:0E
X509v3 Authority Key Identifier:
keyid:57:5A:5D:E0:71:0B:0C:E0:0F:51:87:DE:08:C8:25:E7:F7:87:46:C0
DirName:/C=NZ/L=Wellington/O=Really Irresponsible Authorisation Authority (RIAA)/OU=Cert-stamping/CN=Jackov al-Trades/Email=none@fake.domain
serial:00
Signature Algorithm: md5WithRSAEncryption
27:c3:c3:d8:2e:b2:12:0c:b0:4c:bd:a4:d0:34:77:fe:13:6f:
5e:8d:2c:50:c9:b5:a7:80:16:79:73:68:45:a1:5a:ed:74:d8:
7c:92:f4:04:c0:6b:da:a5:ca:6d:03:2c:cc:f9:32:f9:fb:b9:
be:83:5a:4b:c5:54:1d:07:02:a4:78:c4:90:49:f6:bb:0f:32:
57:86:ff:17:99:7a:a0:85:5f:ee:45:db:28:5f:91:66:d2:35:
54:d7:c2:55:26:ff:ea:b7:3a:d0:3f:fd:6a:dd:26:35:3f:18:
4e:c5:fa:36:d6:71:41:05:a0:4a:49:5d:b7:87:ee:6f:38:17:
9a:4a
-----BEGIN CERTIFICATE-----
MIIEDTCCA3agAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox
EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp
YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy
dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3
DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMDExMDEyMTE0MDNaFw0wMTExMDEy
MTE0MDNaMIGfMQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjEnMCUG
A1UEChMeVGhlIFN0dWZmIG9mIEN1bHR1cmUgYW5kIFRhc3RlMRcwFQYDVQQLEw5T
U0wgZGV2IHRoaW5nczEWMBQGA1UEAxMNdHVuYWxhLXNlcnZlcjEhMB8GCSqGSIb3
DQEJARYSc2VydmVyQGZha2UuZG9tYWluMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
iQKBgQCnB6BwXnZOmEZwDlPjCfQYe8J+itk8ElIkn7924Q7KmcDt+w980RptnB/g
GTplpAAmGVtfDm2isEkMKEDFQ5RVV1DUKIo1PHPzu1oUH6yFurEgJpiakpSW+5Ad
xBgE9X7xIdc0XG4UtptIrIXAUNnPeWeonj+AbP9olUxSlckjQQIDAQABo4IBQDCC
ATwwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQg
Q2VydGlmaWNhdGUwHQYDVR0OBBYEFJ+Rc9CNERMli2gqQFeNlrdiC24OMIHhBgNV
HSMEgdkwgdaAFFdaXeBxCwzgD1GH3gjIJef3h0bAoYG6pIG3MIG0MQswCQYDVQQG
EwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoGA1UEChMzUmVhbGx5IElycmVz
cG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3JpdHkgKFJJQUEpMRYwFAYDVQQL
Ew1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNrb3YgYWwtVHJhZGVzMR8wHQYJ
KoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluggEAMA0GCSqGSIb3DQEBBAUAA4GB
ACfDw9gushIMsEy9pNA0d/4Tb16NLFDJtaeAFnlzaEWhWu102HyS9ATAa9qlym0D
LMz5Mvn7ub6DWkvFVB0HAqR4xJBJ9rsPMleG/xeZeqCFX+5F2yhfkWbSNVTXwlUm
/+q3OtA//WrdJjU/GE7F+jbWcUEFoEpJXbeH7m84F5pK
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCnB6BwXnZOmEZwDlPjCfQYe8J+itk8ElIkn7924Q7KmcDt+w98
0RptnB/gGTplpAAmGVtfDm2isEkMKEDFQ5RVV1DUKIo1PHPzu1oUH6yFurEgJpia
kpSW+5AdxBgE9X7xIdc0XG4UtptIrIXAUNnPeWeonj+AbP9olUxSlckjQQIDAQAB
AoGAJPm/PqDqt8Nl9HB3iY8uhiz/hVvfczjrDkh+7iYsTBV1bDlj2FHB8/nX5Jgx
IUcI8WYzn/tlsdoskZBnpkOrlk0naOsgQk7Osh7Dn5sprRU0ieCgFhD/2DJNjJUE
ZfHrjXwr8LeG2CMa/FzkfkjDPC40gT8plbTOXmLECrjiEnECQQDaukSpJHX4JVtL
08j/mmKoBtBBVyzcSdxxHRXKBp+ivdszHC82oKH4yKwFdsfP6lX7iRsjKWIkdIiA
M9ZDF4TLAkEAw34aSYXWJttRr91HZ+aDXbxTnaaqdrwP1hUJM7dH/a1DQDoxV1vR
SWDX8YHSXgqPsxNtlW8bRtjh5cNWeZICowJAeS1A5MRCZxurHLNUY+dQSO6dadW2
EMUKz8/hRm+s+ShdzE8NCSKtGXtzcgOAZ3vX7ubilfRTXwcAqKYPSlQ5SQJAFg2G
p56abt201FLw+C6PySYyhIlFl4lVe//5fsUBMQO3n2oxILqx3EY5dfwAIC2u0jOx
2/ahrBdRPFsRyTsIYwJBALAxKM5g7Qw0JgQ3gJnczY3/rpwlUhayYRYrNy1pJKp3
hlVv+s5Oy1vXXppVfm830Eii7hsVp5PCFN+jRQhkFqw=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIID9zCCA2CgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox
EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp
YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy
dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3
DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMDExMDEyMTA3MDdaFw0wMTExMDEy
MTA3MDdaMIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoG
A1UEChMzUmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3Jp
dHkgKFJJQUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNr
b3YgYWwtVHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluMIGf
MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCj2aqRye4r8KZ0XKNC68elRVa5AHQY
Igd2K5OYkxACU+UkGzkPoYUz6Uq/kFjXa0lftCxMBvr3FoPb/MMVD+0LeFcJQza5
dMfp3abLe7mttgU2fAQzC6OMetXvqVaBp/rlT0AE2DhzA4g+p51ivkG/pw2zDpra
nHaFsoRKg5puhQIDAQABo4IBFTCCAREwHQYDVR0OBBYEFFdaXeBxCwzgD1GH3gjI
Jef3h0bAMIHhBgNVHSMEgdkwgdaAFFdaXeBxCwzgD1GH3gjIJef3h0bAoYG6pIG3
MIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoGA1UEChMz
UmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3JpdHkgKFJJ
QUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNrb3YgYWwt
VHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluggEAMAwGA1Ud
EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEARuRhKpXa7K2HZEvoIWlLxF/ZrpfB
Zy2ixH25Uk8OnWm/NiS7eQAuR3aRWtEUsMENj1bC9I3hDk6zJVubp8TN0MPlvDvw
gOsMkGGSoumZRPh2aQadcmdBAHSMUMxNHGG0VdhXhodYZCF0H7z0gvKMPVTuIH5U
K2Iq6/aBOw9XbKM=
-----END CERTIFICATE-----
# Edit these to suit
#
# Oh yeah, and please read the README too.
SSL_HOMEDIR=../..
SSL_INCLUDEDIR=$(SSL_HOMEDIR)/include
SSL_LIBDIR=$(SSL_HOMEDIR)
RM=rm -f
CC=gcc
DEBUG_FLAGS=-g -ggdb3 -Wall -Wshadow
INCLUDE_FLAGS=-I$(SSL_INCLUDEDIR)
CFLAGS=$(DEBUG_FLAGS) $(INCLUDE_FLAGS)
COMPILE=$(CC) $(CFLAGS) -c
# Edit, particularly the "-ldl" if not building with "dlfcn" support
LINK_FLAGS=-L$(SSL_LIBDIR) -lssl -lcrypto -ldl
SRCS=buffer.c ip.c sm.c tunala.c
OBJS=buffer.o ip.o sm.o tunala.o
TARGETS=tunala
default: $(TARGETS)
clean:
$(RM) $(OBJS) $(TARGETS) *.bak core
.c.o:
$(COMPILE) $<
tunala: $(OBJS)
$(CC) -o tunala $(OBJS) $(LINK_FLAGS)
# Extra dependencies, should really use makedepend
buffer.o: buffer.c tunala.h
ip.o: ip.c tunala.h
sm.o: sm.c tunala.h
tunala.o: tunala.c tunala.h
#include "tunala.h"
#ifndef NO_BUFFER
void buffer_init(buffer_t *buf)
{
buf->used = 0;
}
void buffer_close(buffer_t *buf)
{
/* Our data is static - nothing needs "release", just reset */
buffer_init(buf);
}
/* Code these simple ones in compact form */
unsigned int buffer_used(buffer_t *buf) {
return buf->used; }
unsigned int buffer_unused(buffer_t *buf) {
return (MAX_DATA_SIZE - buf->used); }
int buffer_full(buffer_t *buf) {
return (buf->used == MAX_DATA_SIZE ? 1 : 0); }
int buffer_notfull(buffer_t *buf) {
return (buf->used < MAX_DATA_SIZE ? 1 : 0); }
int buffer_empty(buffer_t *buf) {
return (buf->used == 0 ? 1 : 0); }
int buffer_notempty(buffer_t *buf) {
return (buf->used > 0 ? 1 : 0); }
unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr,
unsigned int size)
{
unsigned int added = MAX_DATA_SIZE - buf->used;
if(added > size)
added = size;
if(added == 0)
return 0;
memcpy(buf->data + buf->used, ptr, added);
buf->used += added;
return added;
}
unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr,
unsigned int size)
{
unsigned int taken = buf->used;
if(taken > size)
taken = size;
if(taken == 0)
return 0;
if(ptr)
memcpy(ptr, buf->data, taken);
buf->used -= taken;
/* Do we have to scroll? */
if(buf->used > 0)
memmove(buf->data, buf->data + taken, buf->used);
return taken;
}
unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap)
{
unsigned int moved, tomove = from->used;
if((int)tomove > cap)
tomove = cap;
if(tomove == 0)
return 0;
moved = buffer_adddata(to, from->data, tomove);
if(moved == 0)
return 0;
buffer_takedata(from, NULL, moved);
return moved;
}
#ifndef NO_IP
int buffer_from_fd(buffer_t *buf, int fd)
{
unsigned int toread = buffer_unused(buf);
if(toread == 0)
/* Shouldn't be called in this case! */
abort();
toread = read(fd, buf->data + buf->used, toread);
if(toread > 0)
buf->used += toread;
return toread;
}
int buffer_to_fd(buffer_t *buf, int fd)
{
unsigned int towrite = buffer_used(buf);
if(towrite == 0)
/* Shouldn't be called in this case! */
abort();
towrite = write(fd, buf->data, towrite);
if(towrite > 0)
buffer_takedata(buf, NULL, towrite);
return towrite;
}
#endif /* !defined(NO_IP) */
#ifndef NO_OPENSSL
void buffer_from_SSL(buffer_t *buf, SSL *ssl)
{
int ret;
if(!ssl || buffer_full(buf))
return;
ret = SSL_read(ssl, buf->data + buf->used, buffer_unused(buf));
if(ret > 0)
buf->used += ret;
}
void buffer_to_SSL(buffer_t *buf, SSL *ssl)
{
int ret;
if(!ssl || buffer_empty(buf))
return;
ret = SSL_write(ssl, buf->data, buf->used);
if(ret > 0)
buffer_takedata(buf, NULL, ret);
}
void buffer_from_BIO(buffer_t *buf, BIO *bio)
{
int ret;
if(!bio || buffer_full(buf))
return;
ret = BIO_read(bio, buf->data + buf->used, buffer_unused(buf));
if(ret > 0)
buf->used += ret;
}
void buffer_to_BIO(buffer_t *buf, BIO *bio)
{
int ret;
if(!bio || buffer_empty(buf))
return;
ret = BIO_write(bio, buf->data, buf->used);
if(ret > 0)
buffer_takedata(buf, NULL, ret);
}
#endif /* !defined(NO_OPENSSL) */
#endif /* !defined(NO_BUFFER) */
#include "tunala.h"
#ifndef NO_IP
#define IP_LISTENER_BACKLOG 511 /* So if it gets masked by 256 or some other
such value it'll still be respectable */
/* Any IP-related initialisations. For now, this means blocking SIGPIPE */
int ip_initialise(void)
{
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
if(sigaction(SIGPIPE, &sa, NULL) != 0)
return 0;
return 1;
}
int ip_create_listener_split(const unsigned char *ip, unsigned short port)
{
struct sockaddr_in in_addr;
int fd = -1;
int reuseVal = 1;
/* Create the socket */
if((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
goto err;
/* Set the SO_REUSEADDR flag - servers act weird without it */
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)(&reuseVal),
sizeof(reuseVal)) != 0)
goto err;
/* Prepare the listen address stuff */
in_addr.sin_family = AF_INET;
memcpy(&in_addr.sin_addr.s_addr, ip, 4);
in_addr.sin_port = htons(port);
/* Bind to the required port/address/interface */
if(bind(fd, &in_addr, sizeof(struct sockaddr_in)) != 0)
goto err;
/* Start "listening" */
if(listen(fd, IP_LISTENER_BACKLOG) != 0)
goto err;
return fd;
err:
if(fd != -1)
close(fd);
return -1;
}
int ip_create_connection_split(const unsigned char *ip, unsigned short port)
{
struct sockaddr_in in_addr;
int flags, fd = -1;
/* Create the socket */
if((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
goto err;
/* Make it non-blocking */
if(((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0))
goto err;
/* Prepare the connection address stuff */
in_addr.sin_family = AF_INET;
memcpy(&in_addr.sin_addr.s_addr, ip, 4);
in_addr.sin_port = htons(port);
/* Start a connect (non-blocking, in all likelihood) */
if((connect(fd, &in_addr, sizeof(struct sockaddr_in)) != 0) &&
(errno != EINPROGRESS))
goto err;
return fd;
err:
if(fd != -1)
close(fd);
return -1;
}
static unsigned char all_local_ip[] = {0x00,0x00,0x00,0x00};
int ip_parse_address(const char *address, unsigned char **parsed_ip,
unsigned short *parsed_port, int accept_all_ip)
{
char buf[256];
struct hostent *lookup;
unsigned long port;
char *temp;
const char *ptr = strstr(address, ":");
unsigned char *ip = all_local_ip;
if(!ptr) {
/* We assume we're listening on all local interfaces and have
* only specified a port. */
if(!accept_all_ip)
return 0;
ptr = address;
goto determine_port;
}
if((ptr - address) > 255)
return 0;
memset(buf, 0, 256);
memcpy(buf, address, ptr - address);
ptr++;
if((lookup = gethostbyname(buf)) == NULL) {
/* Spit a message to differentiate between lookup failures and
* bad strings. */
fprintf(stderr, "hostname lookup for '%s' failed\n", buf);
return 0;
}
ip = lookup->h_addr_list[0];
determine_port:
if(strlen(ptr) < 1)
return 0;
port = strtoul(ptr, &temp, 10);
if((temp == ptr) || (*temp != '\0') || (port > 65535))
return 0;
*parsed_ip = ip;
*parsed_port = (unsigned short)port;
return 1;
}
int ip_create_listener(const char *address)
{
unsigned char *ip;
unsigned short port;
if(!ip_parse_address(address, &ip, &port, 1))
return -1;
return ip_create_listener_split(ip, port);
}
int ip_create_connection(const char *address)
{
unsigned char *ip;
unsigned short port;
if(!ip_parse_address(address, &ip, &port, 0))
return -1;
return ip_create_connection_split(ip, port);
}
int ip_accept_connection(int listen_fd)
{
return accept(listen_fd, NULL, NULL);
}
#endif /* !defined(NO_IP) */
#include "tunala.h"
#ifndef NO_TUNALA
void state_machine_init(state_machine_t *machine)
{
machine->ssl = NULL;
machine->bio_intossl = machine->bio_fromssl = NULL;
buffer_init(&machine->clean_in);
buffer_init(&machine->clean_out);
buffer_init(&machine->dirty_in);
buffer_init(&machine->dirty_out);
}
void state_machine_close(state_machine_t *machine)
{
if(machine->ssl)
SSL_free(machine->ssl);
/* SSL_free seems to decrement the reference counts already so doing this goes
* kaboom. */
#if 0
if(machine->bio_intossl)
BIO_free(machine->bio_intossl);
if(machine->bio_fromssl)
BIO_free(machine->bio_fromssl);
#endif
buffer_close(&machine->clean_in);
buffer_close(&machine->clean_out);
buffer_close(&machine->dirty_in);
buffer_close(&machine->dirty_out);
state_machine_init(machine);
}
buffer_t *state_machine_get_buffer(state_machine_t *machine, sm_buffer_t type)
{
switch(type) {
case SM_CLEAN_IN:
return &machine->clean_in;
case SM_CLEAN_OUT:
return &machine->clean_out;
case SM_DIRTY_IN:
return &machine->dirty_in;
case SM_DIRTY_OUT:
return &machine->dirty_out;
default:
break;
}
/* Should never get here */
abort();
return NULL;
}
SSL *state_machine_get_SSL(state_machine_t *machine)
{
return machine->ssl;
}
void state_machine_set_SSL(state_machine_t *machine, SSL *ssl, int is_server)
{
if(machine->ssl)
/* Shouldn't ever be set twice */
abort();
machine->ssl = ssl;
/* Create the BIOs to handle the dirty side of the SSL */
if((machine->bio_intossl = BIO_new(BIO_s_mem())) == NULL)
abort();
if((machine->bio_fromssl = BIO_new(BIO_s_mem())) == NULL)
abort();
/* Hook up the BIOs on the dirty side of the SSL */
SSL_set_bio(machine->ssl, machine->bio_intossl, machine->bio_fromssl);
if(is_server)
SSL_set_accept_state(machine->ssl);
else
SSL_set_connect_state(machine->ssl);
/* If we're the first one to generate traffic - do it now otherwise we
* go into the next select empty-handed and our peer will not send data
* but will similarly wait for us. */
state_machine_churn(machine);
}
/* Performs the data-IO loop and returns zero if the machine should close */
int state_machine_churn(state_machine_t *machine)
{
unsigned int loop;
/* Do this loop twice to cover any dependencies about which precise
* order of reads and writes is required. */
for(loop = 0; loop < 2; loop++) {
buffer_to_SSL(&machine->clean_in, machine->ssl);
buffer_to_BIO(&machine->dirty_in, machine->bio_intossl);
buffer_from_SSL(&machine->clean_out, machine->ssl);
buffer_from_BIO(&machine->dirty_out, machine->bio_fromssl);
}
if(machine->ssl == NULL) {
if(buffer_empty(&machine->clean_out))
/* Time to close this state-machine altogether */
return 0;
else
/* Still buffered data on the clean side to go out */
return 1;
}
if(SSL_get_shutdown(machine->ssl)) {
/* An SSL shutdown was underway */
if(buffer_empty(&machine->dirty_out)) {
/* Great, we can seal off the dirty side completely */
if(!state_machine_close_dirty(machine))
return 0;
}
}
/* Either the SSL is alive and well, or the closing process still has
* outgoing data waiting to be sent */
return 1;
}
/* Called when the clean side of the SSL has lost its connection */
int state_machine_close_clean(state_machine_t *machine)
{
/* Well, first thing to do is null out the clean-side buffers - they're
* no use any more. */
buffer_close(&machine->clean_in);
buffer_close(&machine->clean_out);
/* And start an SSL shutdown */
SSL_shutdown(machine->ssl);
/* This is an "event", so flush the SSL of any generated traffic */
state_machine_churn(machine);
if(buffer_empty(&machine->dirty_in) &&
buffer_empty(&machine->dirty_out))
return 0;
return 1;
}
/* Called when the dirty side of the SSL has lost its connection. This is pretty
* terminal as all that can be left to do is send any buffered output on the
* clean side - after that, we're done. */
int state_machine_close_dirty(state_machine_t *machine)
{
buffer_close(&machine->dirty_in);
buffer_close(&machine->dirty_out);
buffer_close(&machine->clean_in);
if(machine->ssl)
SSL_free(machine->ssl);
machine->ssl = NULL;
machine->bio_intossl = machine->bio_fromssl = NULL;
if(buffer_empty(&machine->clean_out))
return 0;
return 1;
}
#endif /* !defined(NO_TUNALA) */
此差异已折叠。
/* Tunala ("Tunneler with a New Zealand accent")
*
* Written by Geoff Thorpe, but endorsed/supported by noone. Please use this is
* if it's useful or informative to you, but it's only here as a scratchpad for
* ideas about how you might (or might not) program with OpenSSL. If you deploy
* this is in a mission-critical environment, and have not read, understood,
* audited, and modified this code to your satisfaction, and the result is that
* all hell breaks loose and you are looking for a new employer, then it proves
* nothing except perhaps that Darwinism is alive and well. Let's just say, *I*
* don't use this in a mission-critical environment, so it would be stupid for
* anyone to assume that it is solid and/or tested enough when even its author
* doesn't place that much trust in it. You have been warned.
*
* With thanks to Cryptographic Appliances, Inc.
*/
#ifndef _TUNALA_H
#define _TUNALA_H
#ifndef NO_SYSTEM_H
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif /* !defined(NO_SYSTEM_H) */
#ifndef NO_OPENSSL
#include <openssl/err.h>
#include <openssl/engine.h>
#include <openssl/ssl.h>
#endif /* !defined(NO_OPENSSL) */
#ifndef NO_BUFFER
/* This is the generic "buffer" type that is used when feeding the
* state-machine. It's basically a FIFO with respect to the "adddata" &
* "takedata" type functions that operate on it. */
#define MAX_DATA_SIZE 16384
typedef struct _buffer_t {
unsigned char data[MAX_DATA_SIZE];
unsigned int used;
} buffer_t;
/* Initialise a buffer structure before use */
void buffer_init(buffer_t *buf);
/* Cleanup a buffer structure - presently not needed, but if buffer_t is
* converted to using dynamic allocation, this would be required - so should be
* called to protect against an explosion of memory leaks later if the change is
* made. */
void buffer_close(buffer_t *buf);
/* Basic functions to manipulate buffers */
unsigned int buffer_used(buffer_t *buf); /* How much data in the buffer */
unsigned int buffer_unused(buffer_t *buf); /* How much space in the buffer */
int buffer_full(buffer_t *buf); /* Boolean, is it full? */
int buffer_notfull(buffer_t *buf); /* Boolean, is it not full? */
int buffer_empty(buffer_t *buf); /* Boolean, is it empty? */
int buffer_notempty(buffer_t *buf); /* Boolean, is it not empty? */
/* Add data to the tail of the buffer, returns the amount that was actually
* added (so, you need to check if return value is less than size) */
unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr,
unsigned int size);
/* Take data from the front of the buffer (and scroll the rest forward). If
* "ptr" is NULL, this just removes data off the front of the buffer. Return
* value is the amount actually removed (can be less than size if the buffer has
* too little data). */
unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr,
unsigned int size);
/* Flushes as much data as possible out of the "from" buffer into the "to"
* buffer. Return value is the amount moved. The amount moved can be restricted
* to a maximum by specifying "cap" - setting it to -1 means no limit. */
unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap);
#ifndef NO_IP
/* Read or write between a file-descriptor and a buffer */
int buffer_from_fd(buffer_t *buf, int fd);
int buffer_to_fd(buffer_t *buf, int fd);
#endif /* !defined(NO_IP) */
#ifndef NO_OPENSSL
/* Read or write between an SSL or BIO and a buffer */
void buffer_from_SSL(buffer_t *buf, SSL *ssl);
void buffer_to_SSL(buffer_t *buf, SSL *ssl);
void buffer_from_BIO(buffer_t *buf, BIO *bio);
void buffer_to_BIO(buffer_t *buf, BIO *bio);
#endif /* !defined(NO_OPENSSL) */
#endif /* !defined(NO_BUFFER) */
#ifndef NO_TUNALA
#ifdef NO_BUFFER
#error "TUNALA section of tunala.h requires BUFFER support"
#endif
typedef struct _state_machine_t {
SSL *ssl;
BIO *bio_intossl;
BIO *bio_fromssl;
buffer_t clean_in, clean_out;
buffer_t dirty_in, dirty_out;
} state_machine_t;
typedef enum {
SM_CLEAN_IN, SM_CLEAN_OUT,
SM_DIRTY_IN, SM_DIRTY_OUT
} sm_buffer_t;
void state_machine_init(state_machine_t *machine);
void state_machine_close(state_machine_t *machine);
buffer_t *state_machine_get_buffer(state_machine_t *machine, sm_buffer_t type);
SSL *state_machine_get_SSL(state_machine_t *machine);
void state_machine_set_SSL(state_machine_t *machine, SSL *ssl, int is_server);
/* Performs the data-IO loop and returns zero if the machine should close */
int state_machine_churn(state_machine_t *machine);
/* Is used to handle closing conditions - namely when one side of the tunnel has
* closed but the other should finish flushing. */
int state_machine_close_clean(state_machine_t *machine);
int state_machine_close_dirty(state_machine_t *machine);
#endif /* !defined(NO_TUNALA) */
#ifndef NO_IP
/* Initialise anything related to the networking. This includes blocking pesky
* SIGPIPE signals. */
int ip_initialise(void);
/* ip is the 4-byte ip address (eg. 127.0.0.1 is {0x7F,0x00,0x00,0x01}), port is
* the port to listen on (host byte order), and the return value is the
* file-descriptor or -1 on error. */
int ip_create_listener_split(const unsigned char *ip, unsigned short port);
/* Same semantics as above. */
int ip_create_connection_split(const unsigned char *ip, unsigned short port);
/* Converts a string into the ip/port before calling the above */
int ip_create_listener(const char *address);
int ip_create_connection(const char *address);
/* Just does a string conversion on its own. NB: If accept_all_ip is non-zero,
* then the address string could be just a port. Ie. it's suitable for a
* listening address but not a connecting address. */
int ip_parse_address(const char *address, unsigned char **parsed_ip,
unsigned short *port, int accept_all_ip);
/* Accepts an incoming connection through the listener. Assumes selects and
* what-not have deemed it an appropriate thing to do. */
int ip_accept_connection(int listen_fd);
#endif /* !defined(NO_IP) */
#endif /* !defined(_TUNALA_H) */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册