]>
git.ipfire.org Git - thirdparty/squid.git/blob - lib/rfcnb/rfcnb-util.c
3 /* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
6 RFCNB Utility Routines ...
8 Copyright (C) Richard Sharpe 1996
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include "rfcnb/rfcnb.h"
29 #include "rfcnb/std-includes.h"
30 #include "rfcnb/rfcnb-priv.h"
31 #include "rfcnb/rfcnb-util.h"
32 #include "rfcnb/rfcnb-io.h"
35 #include <arpa/inet.h>
41 extern void (*Prot_Print_Routine
)(); /* Pointer to protocol print routine */
43 const char *RFCNB_Error_Strings
[] = {
45 "RFCNBE_OK: Routine completed successfully.",
46 "RFCNBE_NoSpace: No space available for a malloc call.",
47 "RFCNBE_BadName: NetBIOS name could not be translated to IP address.",
48 "RFCNBE_BadRead: Read system call returned an error. Check errno.",
49 "RFCNBE_BadWrite: Write system call returned an error. Check errno.",
50 "RFCNBE_ProtErr: A protocol error has occurred.",
51 "RFCNBE_ConGone: Connection dropped during a read or write system call.",
52 "RFCNBE_BadHandle: Bad connection handle passed.",
53 "RFCNBE_BadSocket: Problems creating socket.",
54 "RFCNBE_ConnectFailed: Connection failed. See errno.",
55 "RFCNBE_CallRejNLOCN: Call rejected. Not listening on called name.",
56 "RFCNBE_CallRejNLFCN: Call rejected. Not listening for called name.",
57 "RFCNBE_CallRejCNNP: Call rejected. Called name not present.",
58 "RFCNBE_CallRejInfRes: Call rejected. Name present, but insufficient resources.",
59 "RFCNBE_CallRejUnSpec: Call rejected. Unspecified error.",
60 "RFCNBE_BadParam: Bad parameters passed to a routine.",
61 "RFCNBE_Timeout: IO Operation timed out ..."
65 /* Convert name and pad to 16 chars as needed */
66 /* Name 1 is a C string with null termination, name 2 may not be */
67 /* If SysName is true, then put a <00> on end, else space> */
69 void RFCNB_CvtPad_Name(char *name1
, char *name2
)
77 for (i
= 0; i
< 16; i
++) {
82 c2
= 'A'; /* CA is a space */
87 c1
= (char)((int)c
/16 + (int)'A');
88 c2
= (char)((int)c
%16 + (int)'A');
96 name2
[32] = 0; /* Put in the nll ...*/
100 /* Converts an Ascii NB Name (16 chars) to an RFCNB Name (32 chars)
101 Uses the encoding in RFC1001. Each nibble of byte is added to 'A'
102 to produce the next byte in the name.
104 This routine assumes that AName is 16 bytes long and that NBName has
105 space for 32 chars, so be careful ...
109 void RFCNB_AName_To_NBName(char *AName
, char *NBName
)
115 for (i
=0; i
< 16; i
++) {
119 c1
= (char)((c
>> 4) + 'A');
120 c2
= (char)((c
& 0xF) + 'A');
126 NBName
[32] = 0; /* Put in a null */
130 /* Do the reverse of the above ... */
132 void RFCNB_NBName_To_AName(char *NBName
, char *AName
)
138 for (i
=0; i
< 16; i
++) {
143 c
= (char)(((int)c1
- (int)'A') * 16 + ((int)c2
- (int)'A'));
149 AName
[i
] = 0; /* Put a null on the end ... */
153 /* Print a string of bytes in HEX etc */
155 void RFCNB_Print_Hex(FILE *fd
, struct RFCNB_Pkt
*pkt
, int Offset
, int Len
)
158 char c1
, c2
, outbuf1
[33];
161 struct RFCNB_Pkt
*pkt_ptr
= pkt
;
162 static char Hex_List
[17] = "0123456789ABCDEF";
166 /* We only want to print as much as sepcified in Len */
168 while (pkt_ptr
!= NULL
) {
171 i
< ((Len
> (pkt_ptr
-> len
)?pkt_ptr
-> len
:Len
) - Offset
);
174 c
= pkt_ptr
-> data
[i
+ Offset
];
175 c1
= Hex_List
[c
>> 4];
176 c2
= Hex_List
[c
& 0xF];
181 if (j
== 32) { /* Print and reset */
183 fprintf(fd
, " %s\n", outbuf1
);
190 Len
= Len
- pkt_ptr
-> len
; /* Reduce amount by this much */
191 pkt_ptr
= pkt_ptr
-> next
;
195 /* Print last lot in the buffer ... */
200 fprintf(fd
, " %s\n", outbuf1
);
208 /* Get a packet of size n */
210 struct RFCNB_Pkt
*RFCNB_Alloc_Pkt(int n
)
215 if ((pkt
= (struct RFCNB_Pkt
*)malloc(sizeof(struct RFCNB_Pkt
))) == NULL
) {
217 RFCNB_errno
= RFCNBE_NoSpace
;
218 RFCNB_saved_errno
= errno
;
226 if (n
== 0) return(pkt
);
228 if ((pkt
-> data
= (char *)malloc(n
)) == NULL
) {
230 RFCNB_errno
= RFCNBE_NoSpace
;
231 RFCNB_saved_errno
= errno
;
241 /* Free up a packet */
243 void RFCNB_Free_Pkt(struct RFCNB_Pkt
*pkt
)
246 struct RFCNB_Pkt
*pkt_next
;
249 while (pkt
!= NULL
) {
251 pkt_next
= pkt
-> next
;
253 data_ptr
= pkt
-> data
;
255 if (data_ptr
!= NULL
)
266 /* Print an RFCNB packet */
268 void RFCNB_Print_Pkt(FILE *fd
, char *dirn
, struct RFCNB_Pkt
*pkt
, int len
)
273 /* We assume that the first fragment is the RFCNB Header */
274 /* We should loop through the fragments printing them out */
276 fprintf(fd
, "RFCNB Pkt %s:", dirn
);
278 switch (RFCNB_Pkt_Type(pkt
-> data
)) {
280 case RFCNB_SESSION_MESSAGE
:
282 fprintf(fd
, "SESSION MESSAGE: Length = %i\n", RFCNB_Pkt_Len(pkt
-> data
));
283 RFCNB_Print_Hex(fd
, pkt
, RFCNB_Pkt_Hdr_Len
,
284 #ifdef RFCNB_PRINT_DATA
285 RFCNB_Pkt_Len(pkt
-> data
) - RFCNB_Pkt_Hdr_Len
);
290 if (Prot_Print_Routine
!= 0) { /* Print the rest of the packet */
292 Prot_Print_Routine(fd
, strcmp(dirn
, "sent"), pkt
, RFCNB_Pkt_Hdr_Len
,
293 RFCNB_Pkt_Len(pkt
-> data
) - RFCNB_Pkt_Hdr_Len
);
299 case RFCNB_SESSION_REQUEST
:
301 fprintf(fd
, "SESSION REQUEST: Length = %i\n",
302 RFCNB_Pkt_Len(pkt
-> data
));
303 RFCNB_NBName_To_AName((char *)(pkt
-> data
+ RFCNB_Pkt_Called_Offset
), lname
);
304 fprintf(fd
, " Called Name: %s\n", lname
);
305 RFCNB_NBName_To_AName((char *)(pkt
-> data
+ RFCNB_Pkt_Calling_Offset
), lname
);
306 fprintf(fd
, " Calling Name: %s\n", lname
);
310 case RFCNB_SESSION_ACK
:
312 fprintf(fd
, "RFCNB SESSION ACK: Length = %i\n",
313 RFCNB_Pkt_Len(pkt
-> data
));
317 case RFCNB_SESSION_REJ
:
318 fprintf(fd
, "RFCNB SESSION REJECT: Length = %i\n",
319 RFCNB_Pkt_Len(pkt
-> data
));
321 if (RFCNB_Pkt_Len(pkt
-> data
) < 1) {
322 fprintf(fd
, " Protocol Error, short Reject packet!\n");
324 fprintf(fd
, " Error = %x\n", CVAL(pkt
-> data
, RFCNB_Pkt_Error_Offset
));
329 case RFCNB_SESSION_RETARGET
:
331 fprintf(fd
, "RFCNB SESSION RETARGET: Length = %i\n",
332 RFCNB_Pkt_Len(pkt
-> data
));
334 /* Print out the IP address etc and the port? */
338 case RFCNB_SESSION_KEEP_ALIVE
:
340 fprintf(fd
, "RFCNB SESSION KEEP ALIVE: Length = %i\n",
341 RFCNB_Pkt_Len(pkt
-> data
));
351 /* Resolve a name into an address */
353 int RFCNB_Name_To_IP(char *host
, struct in_addr
*Dest_IP
)
356 int addr
; /* Assumes IP4, 32 bit network addresses */
359 /* Use inet_addr to try to convert the address */
361 if ((addr
= inet_addr(host
)) == INADDR_NONE
) { /* Oh well, a good try :-) */
363 /* Now try a name look up with gethostbyname */
365 if ((hp
= gethostbyname(host
)) == NULL
) { /* Not in DNS */
367 /* Try NetBIOS name lookup, how the hell do we do that? */
369 RFCNB_errno
= RFCNBE_BadName
; /* Is this right? */
370 RFCNB_saved_errno
= errno
;
373 } else { /* We got a name */
375 memcpy((void *)Dest_IP
, (void *)hp
-> h_addr_list
[0], sizeof(struct in_addr
));
378 } else { /* It was an IP address */
380 memcpy((void *)Dest_IP
, (void *)&addr
, sizeof(struct in_addr
));
388 /* Disconnect the TCP connection to the server */
390 int RFCNB_Close(int socket
)
396 /* If we want to do error recovery, here is where we put it */
402 /* Connect to the server specified in the IP address.
403 Not sure how to handle socket options etc. */
405 int RFCNB_IP_Connect(struct in_addr Dest_IP
, int port
)
408 struct sockaddr_in Socket
;
411 /* Create a socket */
413 if ((fd
= socket(PF_INET
, SOCK_STREAM
, 0)) < 0) { /* Handle the error */
415 RFCNB_errno
= RFCNBE_BadSocket
;
416 RFCNB_saved_errno
= errno
;
420 bzero((char *)&Socket
, sizeof(Socket
));
421 memcpy((char *)&Socket
.sin_addr
, (char *)&Dest_IP
, sizeof(Dest_IP
));
423 Socket
.sin_port
= htons(port
);
424 Socket
.sin_family
= PF_INET
;
426 /* Now connect to the destination */
428 if (connect(fd
, (struct sockaddr
*)&Socket
, sizeof(Socket
)) < 0) { /* Error */
431 RFCNB_errno
= RFCNBE_ConnectFailed
;
432 RFCNB_saved_errno
= errno
;
440 /* handle the details of establishing the RFCNB session with remote
445 int RFCNB_Session_Req(struct RFCNB_Con
*con
,
449 struct in_addr
*Dest_IP
,
455 /* Response packet should be no more than 9 bytes, make 16 jic */
457 // char ln1[16], ln2[16], n1[32], n2[32];
460 struct RFCNB_Pkt
*pkt
, res_pkt
;
462 /* We build and send the session request, then read the response */
464 pkt
= RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len
);
468 return(RFCNBE_Bad
); /* Leave the error that RFCNB_Alloc_Pkt gives) */
472 sess_pkt
= pkt
-> data
; /* Get pointer to packet proper */
474 sess_pkt
[RFCNB_Pkt_Type_Offset
] = RFCNB_SESSION_REQUEST
;
475 RFCNB_Put_Pkt_Len(sess_pkt
, RFCNB_Pkt_Sess_Len
-RFCNB_Pkt_Hdr_Len
);
476 sess_pkt
[RFCNB_Pkt_N1Len_Offset
] = 32;
477 sess_pkt
[RFCNB_Pkt_N2Len_Offset
] = 32;
479 RFCNB_CvtPad_Name(Called_Name
, (sess_pkt
+ RFCNB_Pkt_Called_Offset
));
480 RFCNB_CvtPad_Name(Calling_Name
, (sess_pkt
+ RFCNB_Pkt_Calling_Offset
));
482 /* Now send the packet */
486 fprintf(stderr
, "Sending packet: ");
490 if ((len
= RFCNB_Put_Pkt(con
, pkt
, RFCNB_Pkt_Sess_Len
)) < 0) {
492 return(RFCNBE_Bad
); /* Should be able to write that lot ... */
498 fprintf(stderr
, "Getting packet.\n");
503 res_pkt
.len
= sizeof(resp
);
506 if ((len
= RFCNB_Get_Pkt(con
, &res_pkt
, sizeof(resp
))) < 0) {
512 /* Now analyze the packet ... */
514 switch (RFCNB_Pkt_Type(resp
)) {
516 case RFCNB_SESSION_REJ
: /* Didnt like us ... too bad */
518 /* Why did we get rejected ? */
520 switch (CVAL(resp
,RFCNB_Pkt_Error_Offset
)) {
523 RFCNB_errno
= RFCNBE_CallRejNLOCN
;
526 RFCNB_errno
= RFCNBE_CallRejNLFCN
;
529 RFCNB_errno
= RFCNBE_CallRejCNNP
;
532 RFCNB_errno
= RFCNBE_CallRejInfRes
;
535 RFCNB_errno
= RFCNBE_CallRejUnSpec
;
538 RFCNB_errno
= RFCNBE_ProtErr
;
545 case RFCNB_SESSION_ACK
: /* Got what we wanted ... */
550 case RFCNB_SESSION_RETARGET
: /* Go elsewhere */
552 *redirect
= TRUE
; /* Copy port and ip addr */
554 memcpy(Dest_IP
, (resp
+ RFCNB_Pkt_IP_Offset
), sizeof(struct in_addr
));
555 *port
= SVAL(resp
, RFCNB_Pkt_Port_Offset
);
560 default: /* A protocol error */
562 RFCNB_errno
= RFCNBE_ProtErr
;