Bell's Mind Markup Language

by dual

Introduction

Hand scanning is essential to phreaking, as essential as punching and kicking are to martial arts.  Only after thousands and thousands of punches and kicks can one build upon those skills and create new techniques.  Phreaking is the same.  After calling thousands and thousands of numbers, one begins to notice sounds, routing, systems, and intercepts that one wouldn't be aware of otherwise.

Scanning is essential, and propagating the knowledge gained from a scan is just as essential.  Otherwise, that knowledge is worthless to the phreaking community.  Presenting scan information has been a complicated affair over the years.  Up to now, phreaks had to be sleuths to determine accurate information, dealing with incomplete scans, partial numbers, broken acronyms, and other shortcomings.  Furthermore, so much hand scan information is recorded, and still remains, in paper notebooks to this day.

This article discusses a tool to assist phreaks in the creation and dissemination of scan information: Bell's Mind Markup Language.

Bell's Mind Markup Language (BM2L) is the standardization of hand scan presentation.  Bell's Mind Markup Language standardizes hand scan layout, format, and number descriptions.  The standardized format that BM2L provides facilitates efficient hand scan generation and assures scan portability.  Most importantly, BM2L solidifies the phreaking community, bringing disparate data and new phreaks into the fold with a common language and providing a record of scans that can stand the test of time.

The name Bell's Mind Markup Language comes from a website, Bell's Mind.

Bell's Mind is a feature-rich website hosting an impressive telecommunications database and other tools tailored for the phreak community.  One of the capabilities of Bell's Mind is its submission engine for scanned numbers, of which there are over 30,000.  BM2L not only pays homage to Bell's Mind, but also provides a standard for Bell's Mind number description and submission.

BM2L specifies the scan file name, phone number, description, and other aspects of a scan.  The BM2L specification is listed in eight numbered parts, much like an RFC.  It begins with File Name Format.  After the specification, application and BM2L's future conclude the article.

BM2L Specification

1.)  File Name Format

BM2L requires the file name to have the extension .scan.txt.

This highlights the fact that the file is an ASCII-text scan.  It provides universal acceptance across operating systems, web servers and browsers.  It also provides a standard for other tools that expect a certain file name for scans.  Of course, it is helpful to humans as well, letting them know that the file is indeed a hand scan.  Phreaks are free to use any format for the file name base, whether it is the numeric range of the scan, a proper noun, or simply the phreak's handle and an increment.

Examples:

800-555-xxxx.scan.txt
pennsylvania.scan.txt

2.)  Number and Description Format

Scan entries should be in the format: NPA-NXX-XXXX - Description

This provides a common, easily read format, includes the full number for search tools like grep, and requires number and description standardization for other tools.  Effort should be given to keep descriptions to one line for automated tools as well, though readability may necessitate wrapping.  If a description wraps, indent the next line to the beginning of the description to maintain readability.

800-851-6662 - "Thank you for calling. Due to extreme weather conditions, we are unable to answer your call at this time. Please try your call again later."
808-973-4381 - Oahu forecast

3.)  Standard Acronyms

These are the standard acronyms for commonly encountered numbers.  Standard acronyms are most often used by themselves, though they may be included as part of a larger description.  It is helpful to provide an acronym legend with scans, or at least to provide a legend of the acronyms used in the file.

Examples:

414-747-5399 - TTY NIS TTY
808-485-5555 - SIT "Code 4 8. Your call has been connected to a vacant number series..."

4.)  Standard Descriptors

Standard descriptors are one-word descriptions of commonly and uncommonly encountered numbers.  In lower case, they are most often used alone as the description of a number.

  • busy
  • carrier
  • extender
  • fax
  • milliwatt
  • reorder
  • ring out
  • silent

Examples:

505-292-9996 - milliwatt
623-566-9994 - silent

5.)  Secondary Phone Numbers

If a message reads another telephone number, include that number in the description, within a quote of the message or simply at the end of the description.  This provides a launching point for further exploration and information for further investigation.

Example:

800-483-6662 - Verizon West Network Control Center 972-615-6200

6.)  Message and Tandem Codes

Message and tandem codes are included at the end of descriptions within parentheses, for example (027T).  All tandem codes are capitalized and spacing is included so as to match the message.

Example:

505-225-9901 - CBCAD (Leaco message 505-399)

7.)  Carriers

When feasible, carrier connection data should be displayed as the description.  If this is not possible, use the "carrier" standard descriptor discussed earlier.

Examples:

281-230-3203 - carrier
505-541-9999 - CONNECT 31200/ARQ/V34/LAPM/V42BIS
               C                                   
               UQKT2
               User Access Verification
               Username:

8.)  Other Numbers and Descriptions

Numbers and descriptions that do not fit in the above categories should be accounted for with the phreak's best judgment as to ensure readability, accessibility and maintainability.

Utilize the BM2L standard as much as possible, and make suggestions for changes to it, especially when the special number or description is repeatable.

Applications and BM2L's Future

There are a number of applications for BM2L.

For example, we can write our own syntax highlighting for GNU nano that makes scans more accessible and colorful.  Carriers stand out as bright yellow, for example.

This demonstrates that using an open standard allows for the most personalization.  An agreed-upon standard allows tools and processes to be created for customizable uses.

Another example is number entry into a database.  The BM2L scan format allows the simple creation of large scan databases.  And, again, what one can then do with a relational database of thousands of scanned numbers is anyone's guess.  We can, for example, write a Perl script that creates the SQL statements to enter scans into a MySQL database.

Both of these example scripts are available from the 2600 code repository.  I have also made available a Perl script, handscan.pl, and a website, handscan.net, that generate BM2L-compliant hand scan lists.

Suggestions have already been to BM2L and updates will be maintained in the "Old Skool Phreaking" section at the Binary Revolution forums.

The addition of made "resident" and "business" standard descriptors is being considered, to provide both discretion regarding personally identifiable information and a way to speed scanning.

The standard descriptor "pron" has also been suggested for obvious reasons.

References

www.bellsmind.net/Bells_Mind/Welcome.html

www.nano-editor.org

dualisanoob.com/linux/perl/handscan.txt

www.handscan.net

www.binrev.com/forums/index.php?showforum=21


handscan.pl:

#!/usr/bin/perl -w

# handscan.pl - by dual
#
# Generates number lists for handscanning
# (see also http://www.handscan.net)
#########################################

use strict;
use List::Util 'shuffle';

#***************************************************************************
#
# Main program
#
#***************************************************************************

# Declare
my $type;
my @tmparray;
my $random = 0;
my ( $npa, $nxx, $ext );
my ( $firsttwo, $firstone );
my ( $temp1, $temp2, $temp3 );
my $NPA_ERR_MSG =
  "The Numbering Plan Area (NPA), or area code, must adhere to the North
American Numbering Plan Administration (NANPA) guidelines. Please see
http://www.nanpa.com/area_codes/index.html for more information.
";
my $NXX_ERR_MSG =
  "The NXX, or exchange, must adhere to the Alliance for Telecommunications
Industry Solutions (ATIS) Industry Numbering Committee (INC) guidelines.
Please see http://www.atis.org/inc/Docs/finaldocs/CoCAG-Final-01-18-08.doc
for more information.
";
my $STD_ERR_MSG =
  "handscan.pl - Generates scan lists of ten-digit, North American
	      telephone numbers in the form of NPA-NXX-XXXX

Usage: handscan -a <NXX> <XXXX>
       handscan -e <NPA> <XXXX>
       handscan -h <NPA> <NXX> <XX>
       handscan -t <NPA> <NXX> <X>
       handscan -u <NPA> <NXX>

-a => Area code scan
-e => Exchange scan
-h => One hundred scan
-t => One thousand scan
-u => Ultimate scan, i.e. ten thousand scan

Use -r before the scan type to randomize your scan, e.g. handscan -r -u 212 209.
";
my $OH_ERR_MSG =
  "Enter the first two digits of the extension. For example, enter \"99\"
to scan 9900 - 9999.
";
my $OT_ERR_MSG =
  "Enter the first digit of the extension. For example, enter \"9\" to
scan 9000 - 9999.
";

# Usage if no args
error($STD_ERR_MSG) unless @ARGV;

# Determine if random scan
if ( $ARGV[0] =~ /^-r$/ ) {
    shift;
    $random = 1;
    ( $type = shift ) ? getncheck() : error($STD_ERR_MSG);
}
else {
    $type = shift;
    getncheck();
}

# Get and check arg(s) and call
# the appropriate function
sub getncheck {
    if ( $type =~ /^-a$/ ) {
        error($STD_ERR_MSG) unless defined( $temp1 = $ARGV[0] );
        error($STD_ERR_MSG) unless defined( $temp2 = $ARGV[1] );
        error($STD_ERR_MSG) unless ( $temp1 =~ /^(\d{3})$/ );
        $nxx = $1;
        error($NXX_ERR_MSG) if AREA_ERR($nxx);
        error($STD_ERR_MSG) unless ( $temp2 =~ /^(\d{4})$/ );
        $ext = $1;
        area();
    }
    elsif ( $type =~ /^-e$/ ) {
        error($STD_ERR_MSG) unless defined( $temp1 = $ARGV[0] );
        error($STD_ERR_MSG) unless defined( $temp2 = $ARGV[1] );
        error($STD_ERR_MSG) unless ( $temp1 =~ /^(\d{3})$/ );
        $npa = $1;
        error($NPA_ERR_MSG) if NPA_ERR($npa);
        error($STD_ERR_MSG) unless ( $temp2 =~ /^(\d{4})$/ );
        $ext = $1;
        exchange();
    }
    elsif ( $type =~ /^-h$/ ) {
        error($STD_ERR_MSG) unless defined( $temp1 = $ARGV[0] );
        error($STD_ERR_MSG) unless defined( $temp2 = $ARGV[1] );
        error($STD_ERR_MSG) unless defined( $temp3 = $ARGV[2] );
        error($STD_ERR_MSG) unless ( $temp1 =~ /^(\d{3})$/ );
        $npa = $1;
        error($NPA_ERR_MSG) if NPA_ERR($npa);
        error($STD_ERR_MSG) unless ( $temp2 =~ /^(\d{3})$/ );
        $nxx = $1;
        error($NXX_ERR_MSG) if NXX_ERR( $nxx, $npa );
        error($OH_ERR_MSG) unless ( $temp3 =~ /^(\d{2})$/ );
        $firsttwo = $1;
        hundred();
    }
    elsif ( $type =~ /^-t$/ ) {
        error($STD_ERR_MSG) unless defined( $temp1 = $ARGV[0] );
        error($STD_ERR_MSG) unless defined( $temp2 = $ARGV[1] );
        error($STD_ERR_MSG) unless defined( $temp3 = $ARGV[2] );
        error($STD_ERR_MSG) unless ( $temp1 =~ /^(\d{3})$/ );
        $npa = $1;
        error($NPA_ERR_MSG) if NPA_ERR($npa);
        error($STD_ERR_MSG) unless ( $temp2 =~ /^(\d{3})$/ );
        $nxx = $1;
        error($NXX_ERR_MSG) if NXX_ERR( $nxx, $npa );
        error($OT_ERR_MSG) unless ( $temp3 =~ /^(\d{1})$/ );
        $firstone = $1;
        thousand();
    }
    elsif ( $type =~ /^-u$/ ) {
        error($STD_ERR_MSG) unless defined( $temp1 = $ARGV[0] );
        error($STD_ERR_MSG) unless defined( $temp2 = $ARGV[1] );
        error($STD_ERR_MSG) unless ( $temp1 =~ /^(\d{3})$/ );
        $npa = $1;
        error($NPA_ERR_MSG) if NPA_ERR($npa);
        error($STD_ERR_MSG) unless ( $temp2 =~ /^(\d{3})$/ );
        $nxx = $1;
        error($NXX_ERR_MSG) if NXX_ERR( $nxx, $npa );
        ultimate();
    }
    else { error($STD_ERR_MSG); }
}

#***************************************************************************
#
# Error functions
#
#***************************************************************************

# Print error message
sub error {
    if ( my $err_msg = shift ) {
        print $err_msg;
    }
    exit 1;
}

# Handle NPA errors
sub NPA_ERR {
    if (
           $_[0] < 200
        or $_[0] =~ /[2-79](\d)\1|
				     8([2-59])\1|
				     \d11|
				     \d9\d|
				     37\d|
				     96\d/x
      )
    {
        return 1;
    }
    else { return 0; }
}

# Handle NXX errors
sub NXX_ERR {
    if ( $_[0] < 200 ) { return 1; }
    elsif ( $_[0] =~ /\d11|$_[1]|555|700|95(0|8|9)/
        and $npa !~ /8(00|66|77|88)/ )
    {
        return 1;
    }
    else { return 0; }
}

# Handle area code scan NXX errors
sub AREA_ERR {
    if    ( $_[0] < 200 )                       { return 1; }
    elsif ( $_[0] =~ /\d11|555|700|95(0|8|9)/ ) { return 1; }
    else                                        { return 0; }
}

#***************************************************************************
#
# Output functions
#
#***************************************************************************

# Randomize scan
sub randomize {
    if ($random) {
        my @ranarray = shuffle(@tmparray);
        print @ranarray;
    }
    else { print @tmparray; }
}

# Area code scan
sub area {
    my @area_codes = qw(
      201 202 203 204 205 206 207 208 209 210 212 213 214 215 216 217 218 219 224 225 226 228 229 231 234
      239 240 242 246 248 250 251 252 253 254 256 260 262 264 267 268 269 270 276 281 284 289 301 302 303
      304 305 306 307 308 309 310 312 313 314 315 316 317 318 319 320 321 323 325 330 331 334 336 337 339
      340 345 347 351 352 360 361 386 401 402 403 404 405 406 407 408 409 410 412 413 414 415 416 417 418
      419 423 424 425 430 432 434 435 438 440 441 443 450 456 469 473 478 479 480 484 501 502 503 504 505
      506 507 508 509 510 512 513 514 515 516 517 518 519 520 530 540 541 551 559 561 562 563 567 570 571
      573 574 575 580 581 585 586 587 601 602 603 604 605 606 607 608 609 610 612 613 614 615 616 617 618
      619 620 623 626 630 631 636 641 646 647 649 650 651 657 660 661 662 664 670 671 678 682 684 701 702
      703 704 705 706 707 708 709 710 712 713 714 715 716 717 718 719 720 724 727 731 732 734 740 754 757
      758 760 762 763 765 767 769 770 772 773 774 775 778 779 780 781 784 785 786 787 800 801 802 803 804
      805 806 807 808 809 810 812 813 814 815 816 817 818 819 828 829 830 831 832 843 845 847 848 850 856
      857 858 859 860 862 863 864 865 866 867 868 869 870 876 877 878 888 901 902 903 904 905 906 907 908
      909 910 912 913 914 915 916 917 918 919 920 925 928 931 936 937 939 940 941 947 949 951 952 954 956
      970 971 972 973 978 979 980 985 989
    );

    foreach my $code (@area_codes) {
        push @tmparray, "$code-$nxx-$ext - \n" unless ( $code =~ /$nxx/ );
    }
    randomize();
    exit 0;
}

# Exchange scan
sub exchange {
    my $i = 200;
    while ( $i < 1000 ) {
        if ( $i =~ /\d11|$npa|555|700|95(0|8|9)/ and $npa !~ /8(00|66|77|88)/ )
        {
            $i++;
            next;
        }
        my $j = sprintf( "%03d", $i );
        push @tmparray, "$npa-$i-$ext - \n";
        $i++;
    }
    randomize();
    exit 0;
}

# One hundred scan
sub hundred {
    my $i = 0;
    while ( $i < 100 ) {
        my $j = sprintf( "%02d", $i );
        push @tmparray, "$npa-$nxx-$firsttwo$j - \n";
        $i++;
    }
    randomize();
    exit 0;
}

# One thousand scan
sub thousand {
    my $i = 0;
    while ( $i < 1000 ) {
        my $j = sprintf( "%03d", $i );
        push @tmparray, "$npa-$nxx-$firstone$j - \n";
        $i++;
    }
    randomize();
    exit 0;
}

# Ultimate scan
sub ultimate {
    my $i = 0;
    while ( $i < 10000 ) {
        my $j = sprintf( "%04d", $i );
        push @tmparray, "$npa-$nxx-$j - \n";
        $i++;
    }
    randomize();
    exit 0;
}

process4mysql.pl:

#!/usr/bin/perl -w

# process4mysql.pl -

use strict;

my $scan = shift or die ">>> Need a scan...";
open my $file, '<', $scan or die ">>> Can't open scan: $!";

while (<$file>) {
        chomp;
        my @array = split(/ - /, $_);
        $array[0] =~ /^(\d{3})-(\d{3})-(\d{4})/;
        my $npa = $1;
        my $nxx = $2;
        my $ext = $3;
        $array[1] =~ s/\'/\\'/g;
        print "INSERT INTO phonebook (`npa`, `nxx`, `ext`, `description`, `type`) VALUES ('$npa', '$nxx', '$ext', '$array[1]', '$scan')\;\n";
}

close $file;

Code: handscan.pl

Code: process4mysql.pl

Code: nano - Hand Scan Syntax Highlighting

Return to $2600 Index