/* tsbridge.c: transport bridge - jpo version ! */
static char *rcsid
= "$Header: /f/osi/others/tsbridge/RCS/tsbridge.c,v 7.10 91/02/22 09:34:37 mrose Interim $";
* $Header: /f/osi/others/tsbridge/RCS/tsbridge.c,v 7.10 91/02/22 09:34:37 mrose Interim $
* Contributed by Julian Onions, Nottingham University in the UK
* Revision 7.10 91/02/22 09:34:37 mrose
* Revision 7.9 91/01/24 14:52:19 mrose
* Revision 7.8 90/11/04 19:15:29 mrose
* Revision 7.6 90/08/08 14:04:48 mrose
* Revision 7.5 90/07/09 14:43:01 mrose
* Revision 7.4 90/03/19 14:27:00 mrose
* Revision 7.2 90/01/11 18:36:55 mrose
* Revision 7.1 89/11/27 05:43:28 mrose
* Revision 7.0 89/11/23 22:11:12 mrose
* Acquisition, use, and distribution of this module and related
* materials are subject to the restrictions of a license agreement.
* Consult the Preface in the User's Manual for the full terms of
static int nbits
= FD_SETSIZE
;
"tsbridge.log", NULLCP
, NULLCP
,
LLOG_FATAL
| LLOG_EXCEPTIONS
| LLOG_NOTICE
, LLOG_FATAL
,
-1, LLOGCLS
| LLOGCRT
| LLOGZER
, NOTOK
LLog
*pgm_log
= &_pgm_log
;
static char *myname
= "tsbridge";
#define CONN_FORCEMUNGE 010
ContTbl con_tbl
[FD_SETSIZE
];
static struct TSAPaddr
*maketa ();
static struct TSAPaddr
*getnewta ();
static ContTbl
*find_connection ();
static void read_file ();
static void adios (), advise ();
static void ts_adios (), ts_advise ();
static void ts_close (), ts_discon ();
static void tsbridge (), do_the_biz (), copy_tsdu (), arginit (), envinit ();
struct TSAPdisconnect tds
;
register struct TSAPdisconnect
*td
= &tds
;
struct TSAPaddr tas
, *ta
= &tas
;
for (vecp
= 0; vecp
< con_tbl_cnt
; vecp
++) {
advise (LLOG_TRACE
, NULLCP
, "Listening on %s",
taddr2str (&con_tbl
[vecp
].src
));
if (TNetListen (&con_tbl
[vecp
].src
, td
) == NOTOK
) {
advise (LLOG_FATAL
, NULLCP
, "Listen failed on \"%s\"",
taddr2str (&con_tbl
[vecp
].src
));
ts_adios (td
, "listen failed");
if (TNetAcceptAux (&vecp
, vec
, NULLIP
, ta
, 0, NULLFD
, NULLFD
,
NULLFD
, NOTOK
, td
) == NOTOK
)
ts_adios (td
, "accept failed");
advise (LLOG_TRACE
, NULLCP
, "accepted new connection");
switch (TNetFork (vecp
, vec
, td
)) {
ll_hdinit (pgm_log
, myname
);
tsbridge (vecp
, vec
, ta
);
ts_advise (td
, LLOG_EXCEPTIONS
, "TNetFork failed");
static void tsbridge (vecp
, vec
, ta
)
register struct TSAPstart
*ts
= &tss
;
struct TSAPdisconnect tds
;
register struct TSAPdisconnect
*td
= &tds
;
struct TSAPconnect
*tc
= &tcs
;
if (TInit (vecp
, vec
, ts
, td
) == NOTOK
)
ts_adios (td
, "T-CONNECT.INDICATION failed");
advise (LLOG_NOTICE
, NULLCP
,
"T-CONNECT.INDICATION: <%d, %s, %s, %d, %d>",
ts
-> ts_sd
, taddr2str (&ts
-> ts_calling
),
taddr2str (&ts
-> ts_called
),
ts
-> ts_expedited
, ts
-> ts_tsdusize
);
ctp
= find_connection (ta
);
ts_close (sd
, "Unknown listener address");
advise (LLOG_TRACE
, NULLCP
, "Accepted from address %s",
taddr2str (&ctp
-> src
));
tota
= getnewta (&ts
-> ts_called
, sd
, ctp
);
fromta
= maketa (&ts
-> ts_calling
, tota
-> ta_addrs
[0].na_stack
, ctp
);
if ((ctp
-> flags
& CONN_TRANS
) == 0) {
advise (LLOG_EXCEPTIONS
, NULLCP
,
"%d octets initial user-data",
ts_close (sd
, "initial user-data not allowed");
advise (LLOG_NOTICE
, NULLCP
,
"T-CONNECT.REQUEST: <%s, %s, %d, 0x%x/%d>",
taddr2str (fromta
), taddr2str (tota
), ts
-> ts_expedited
,
ts
-> ts_data
, ts
-> ts_cc
);
if (TConnRequest (fromta
, tota
, ts
-> ts_expedited
,
ts
-> ts_data
, ts
-> ts_cc
, &ts
-> ts_qos
,
ts_close (sd
, "connection establishment failed");
ts_adios(td
, "T-CONNECT.REQUEST");
if (TConnResponse (sd
, NULLTA
,
tc
-> tc_expedited
, tc
-> tc_data
, tc
-> tc_cc
,
&tc
-> tc_qos
, td
) == NOTOK
) {
ts_close (sd
, "connection establishment failed");
ts_close (tc
-> tc_sd
, "connection establishment failed");
ts_adios (td
, "T-CONNECT.RESPONSE");
do_the_biz (sd
, tc
-> tc_sd
);
static void do_the_biz (sd1
, sd2
)
struct TSAPdisconnect tds
;
register struct TSAPdisconnect
*td
= &tds
;
if (TSelectMask (sd1
, &rmask
, &nfds
, td
) == NOTOK
|| TSelectMask (sd2
, &rmask
, &nfds
, td
) == NOTOK
)
ts_adios (td
, "TSelectMask failed");
if (xselect (nfds
, &imask
, NULLFD
, NULLFD
, NOTOK
) == NOTOK
)
adios ("select", "failed");
if (FD_ISSET (sd1
, &imask
))
if (FD_ISSET (sd2
, &imask
))
static void copy_tsdu (s1
, s2
)
struct TSAPdisconnect tds
;
register struct TSAPdisconnect
*td
= &tds
;
register struct TSAPdata
*tx
= &txs
;
SLOG (pgm_log
, LLOG_DEBUG
, NULLCP
, ("copy_tsdu (%d -> %d)", s1
, s2
));
if (TReadRequest (s1
, tx
, OK
, td
) == NOTOK
) {
switch (td
-> td_reason
) {
ts_advise (td
, LLOG_TRACE
, "TReadRequest");
ts_adios (td
, "TReadRequest");
if (tx
-> tx_expedited
) {
SLOG (pgm_log
, LLOG_DEBUG
, NULLCP
, ("TExpdRequest"));
p
= qb2str (&tx
-> tx_qbuf
);
result
= TExpdRequest (s2
, p
, tx
-> tx_cc
, td
);
for (qb
= tx
-> tx_qbuf
.qb_forw
; qb
!= &tx
-> tx_qbuf
;
uvec
[uiocnt
].uv_base
= qb
-> qb_data
;
uvec
[uiocnt
++].uv_len
= qb
-> qb_len
;
adios (NULLCP
, "Internal buffer overflow");
uvec
[uiocnt
].uv_base
= NULLCP
;
if (tx
-> tx_cc
!= total
)
advise (LLOG_EXCEPTIONS
, NULLCP
,
"Mismatch in data %d != %d",
SLOG (pgm_log
, LLOG_DEBUG
, NULLCP
, ("TWriteRequest"));
result
= TWriteRequest (s2
, uvec
, td
);
if (td
-> td_reason
== DR_NORMAL
)
ts_adios (td
, tx
-> tx_expedited
? "T-EXPEDITED-DATA.REQUEST"
static void ts_discon (td
, sd
)
struct TSAPdisconnect
*td
;
ts_close (sd
, "Normal Disconnect");
ts_advise (td
, LLOG_NOTICE
, "T-DISCONNECT.INDICATION");
static void ts_close (sd
, event
)
struct TSAPdisconnect tds
;
register struct TSAPdisconnect
*td
= &tds
;
if (strlen (event
) >= TD_SIZE
)
if (TDiscRequest (sd
, event
, event
? strlen (event
) + 1: 0, td
)
ts_advise (td
, LLOG_EXCEPTIONS
, "T-DISCONNECT.REQUEST");
static void ts_adios (td
, event
)
register struct TSAPdisconnect
*td
;
ts_advise (td
, LLOG_EXCEPTIONS
, event
);
static void ts_advise (td
, code
, event
)
register struct TSAPdisconnect
*td
;
(void) sprintf (buffer
, "[%s] %*.*s",
TErrString (td
-> td_reason
),
td
-> td_cc
, td
-> td_cc
, td
-> td_data
);
(void) sprintf (buffer
, "[%s]", TErrString (td
-> td_reason
));
advise (code
, NULLCP
, "%s: %s", event
, buffer
);
static struct TSAPaddr
*getnewta (ta
, sd
, ctp
)
static struct TSAPaddr newta
;
struct TSAPaddr
*nta
= &newta
;
if (ctp
-> flags
& CONN_TRANS
) { /* make transparent address */
*nta
= ctp
-> dest
; /* struct copy */
nta
-> ta_selectlen
= ta
-> ta_selectlen
;
bcopy (ta
-> ta_selector
, nta
-> ta_selector
,
/* do the real TS bridge stuff */
if ((m
= ta
-> ta_selectlen
) == 0) {
ts_close (sd
, "no transport selector");
adios (NULLCP
, "no transport selector");
/* does this look like an encoded TSEL? */
n
= ta
-> ta_selector
[0];
advise (LLOG_TRACE, NULLCP, "n=%d,m=%d s[0] = %d, s[1] = %d",
n, m, ta -> ta_selector[0], ta -> ta_selector[1]);
ta
-> ta_selector
[0] == ta
-> ta_selector
[1] &&
n
> 2 && n
<= m
- 2) { /* encoded! */
bzero ((char *)nta
, sizeof *nta
);
nta
-> ta_selectlen
= m
- n
- 2;
if (nta
-> ta_selectlen
> 0)
bcopy (&ta
-> ta_selector
[n
+2], nta
-> ta_selector
,
if (norm2na (&ta
-> ta_selector
[2], n
, nta
-> ta_addrs
) != OK
) {
ts_close (sd
, "undecodable address");
adios (NULLCP
, "Can't decode address");
bcopy (ta
-> ta_selector
, buffer
, ta
-> ta_selectlen
);
buffer
[ta
-> ta_selectlen
] = NULL
;
if ((nta
= str2taddr (buffer
)) == NULLTA
) {
ts_close (sd
, "unable to translate address");
adios (NULLCP
, "unable to translate \"%s\"", buffer
);
static struct TSAPaddr
*maketa (ta
, type
, ctp
)
static struct TSAPaddr newta
;
register struct TSAPaddr
*nta
= &newta
;
struct PSAPaddr
*pa
= &pas
;
if (ctp
-> flags
& CONN_NOMUNGE
) {
*nta
= *ta
; /* struct copy */
if (!(ctp
-> flags
& CONN_NOMUNGE
) || (ctp
-> flags
& CONN_FORCEMUNGE
)) {
bzero ((char *)pa
, sizeof *pa
);
pa
-> pa_addr
.sa_addr
= *ta
;
if ((p
= _paddr2str (pa
, NULLNA
, -1)) == NULL
||
(nta
-> ta_selectlen
= strlen (p
)) >= TSSIZE
) {
if (ctp
-> flags
& CONN_STRICT
)
adios (NULLCP
, "new selector not encodable");
advise (LLOG_NOTICE
, NULLCP
,
"new selector not encodable");
bcopy (p
, nta
-> ta_selector
, TSSIZE
);
struct NSAPaddr
*nna
= na2norm (&ta
-> ta_addrs
[0]);
if ((nta
-> ta_selectlen
= 2 + nna
-> na_addrlen
+
ta
-> ta_selectlen
) >= TSSIZE
)
bcopy (nna
-> na_address
, &nta
-> ta_selector
[2],
bcopy (ta
-> ta_selector
,
&nta
-> ta_selector
[2 + nna
-> na_addrlen
],
nta
-> ta_selector
[0] = nta
-> ta_selector
[1] =
for (i
= 0; i
< ctp
-> src
.ta_naddr
; i
++) {
if (ctp
-> src
.ta_addrs
[i
].na_stack
== type
) {
nta
-> ta_addrs
[0] = ctp
->src
.ta_addrs
[i
];
* This requires an explanation:
* If NOMUNGE && FORCEMUNGE we have a semi-transparent bridge
* and since [at least on my machine] the recipient of a "transparent"
* call sees it as coming from the bridge host, ie the effect is that
* of a strict call, the structure that is now in nta, viz:
* "calling address"/calling address
* is going to get clobbered and appear at the final host as originating
* "calling address"/bridge host
* anyway. This is what I want.
if ((ctp
-> flags
& CONN_NOMUNGE
)
&& (ctp
-> flags
& CONN_FORCEMUNGE
)
&& !(ctp
-> flags
& CONN_STRICT
)) {
if (ctp
-> flags
& CONN_STRICT
)
adios (NULLCP
, "not listening on this network (%d)", type
);
advise (LLOG_NOTICE
, NULLCP
,
"not listening on this network (%d)", type
);
static ContTbl
*find_connection (ta
)
struct NSAPaddr
*na1
, *na2
;
for (ctp
= con_tbl
; ctp
< &con_tbl
[con_tbl_cnt
]; ctp
++) {
for (na1
= &ctp
-> src
.ta_addrs
[0];
na1
< &ctp
-> src
.ta_addrs
[ctp
->src
.ta_naddr
]; na1
++) {
for (na2
= &ta
-> ta_addrs
[0];
na2
< &ta
-> ta_addrs
[ta
->ta_naddr
]; na2
++) {
if (na1
-> na_stack
!= na2
-> na_stack
)
switch (na1
-> na_stack
) {
if (na1
-> na_addrlen
== na2
-> na_addrlen
&&
bcmp (na1
-> na_address
, na2
-> na_address
,
na1
-> na_addrlen
) == 0 &&
ta
-> ta_selectlen
== ctp
-> src
.ta_selectlen
&&
bcmp (ta
-> ta_selector
, ctp
-> src
.ta_selector
,
ta
-> ta_selectlen
) == 0)
if (na1
-> na_port
== na2
-> na_port
&&
strcmp (na1
-> na_domain
, na2
-> na_domain
) == 0)
if (na1
-> na_dtelen
== na2
-> na_dtelen
&&
bcmp (na1
-> na_dte
, na2
-> na_dte
,
na1
-> na_dtelen
) == 0 &&
na1
-> na_pidlen
== na2
-> na_pidlen
&&
bcmp (na1
-> na_pid
, na2
-> na_pid
,
static void arginit (vec
)
register struct TSAPaddr
*ta
;
if (myname
= rindex (*vec
, '/'))
if (myname
== NULL
|| *myname
== NULL
)
for (vec
++; ap
= *vec
; vec
++) {
if ((ap
= *++vec
) == NULL
|| *ap
== '-')
adios (NULLCP
, "usage: %s -T tailorfile", myname
);
(void) isodesetailor (ap
);
ll_hdinit (pgm_log
, myname
);
if ((ap
= *++vec
) == NULL
|| *ap
== '-')
adios (NULLCP
, "usage: %s -a address", myname
);
if ((ta
= str2taddr (ap
)) == NULLTA
)
adios (NULLCP
, "bad address \"%s\"", ap
);
con_tbl
[0].src
= *ta
; /* struct copy */
con_tbl
[0].flags
|= CONN_STRICT
;
adios (NULLCP
, "unknown switch -%s", ap
);
ll_hdinit (pgm_log
, myname
);
if ((ta
= str2taddr (tsb_default_address
)) == NULLTA
)
adios (NULLCP
, "bad default address \"%s\"",
con_tbl
[0].src
= *ta
; /* struct copy */
static void read_file (file
)
if (strcmp (file
, "-") == 0)
else if ((fp
= fopen (file
, "r")) == NULL
)
adios (file
, "Can't open ");
while (fgets (buf
, sizeof buf
, fp
) != NULLCP
) {
if (buf
[0] == '#' || buf
[0] == '\n')
vecp
= sstr2arg (buf
, 50, vec
, " \t,\n");
if ((ta
= str2taddr (vec
[0])) == NULLTA
)
adios (NULLCP
, "Bad address \"%s\" in file %s", vec
[0], file
);
ctp
= &con_tbl
[con_tbl_cnt
];
ctp
-> src
= *ta
; /* struct copy */
for (i
= 1; i
< vecp
; i
++) {
ctp
-> flags
|= CONN_STRICT
;
ctp
-> flags
|= CONN_TRANS
;
ctp
-> flags
|= CONN_NOMUNGE
;
ctp
-> flags
|= CONN_FORCEMUNGE
;
adios (NULLCP
, "Unknown option -%c", *ap
);
if ((ta
= str2taddr (ap
)) == NULLTA
)
adios (NULLCP
, "Bad address \"%s\" in file %s",
ctp
-> dest
= *ta
; /* struct copy */
ctp
-> flags
|= (CONN_TRANS
|CONN_NOMUNGE
);
if (strcmp (file
, "-") != 0)
nbits
= getdtablesize ();
if (!(debug
= isatty (2))) {
for (i
= 0; i
< 5; i
++) {
if ((sd
= open ("/dev/null", O_RDWR
)) == NOTOK
)
adios ("/dev/null", "unable to read");
(void) dup2 (sd
, 0), (void) close (sd
);
advise (LLOG_EXCEPTIONS
, "failed", "setsid");
if ((sd
= open ("/dev/tty", O_RDWR
)) != NOTOK
) {
(void) ioctl (sd
, TIOCNOTTY
, NULLCP
);
(void) signal (SIGINT
, SIG_IGN
);
(void) signal (SIGQUIT
, SIG_IGN
);
ll_dbinit (pgm_log
, myname
);
#ifndef sun /* damn YP... */
for (sd
= 3; sd
< nbits
; sd
++)
if (pgm_log
-> ll_fd
!= sd
)
(void) signal (SIGPIPE
, SIG_IGN
);
ll_hdinit (pgm_log
, myname
);
advise (LLOG_NOTICE
, NULLCP
, "starting");
static void adios (va_alist
)
_ll_log (pgm_log
, LLOG_FATAL
, ap
);
static void adios (what
, fmt
)
static void advise (va_alist
)
_ll_log (pgm_log
, code
, ap
);
static void advise (code
, what
, fmt
)
advise (code
, what
, fmt
);