blob: 46ea2dd76e1c0c363e5e9e7e21e747ba6dc2a021 [file] [log] [blame]
Sylvain Munaut48767122010-12-26 00:11:19 +01001#!/usr/bin/env python
2
3#
4# Utility to generate the HLR
5#
6#
7# Copyright (C) 2010 Sylvain Munaut <tnt@246tNt.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
21#
22
23from optparse import OptionParser
24
25from ccc import StateManager, CardParametersGenerator, isnum
26from pySim.utils import h2b
27
28
29#
30# OpenBSC HLR Writing
31#
32
33def _dbi_binary_quote(s):
34 # Count usage of each char
35 cnt = {}
36 for c in s:
37 cnt[c] = cnt.get(c, 0) + 1
38
39 # Find best offset
40 e = 0
41 m = len(s)
42 for i in range(1, 256):
43 if i == 39:
44 continue
45 sum_ = cnt.get(i, 0) + cnt.get((i+1)&0xff, 0) + cnt.get((i+39)&0xff, 0)
46 if sum_ < m:
47 m = sum_
48 e = i
49 if m == 0: # No overhead ? use this !
50 break;
51
52 # Generate output
53 out = []
54 out.append( chr(e) ) # Offset
55 for c in s:
56 x = (256 + ord(c) - e) % 256
57 if x in (0, 1, 39):
58 out.append('\x01')
59 out.append(chr(x+1))
60 else:
61 out.append(chr(x))
62
63 return ''.join(out)
64
65
66def hlr_write_cards(filename, network, cards):
67
68 import sqlite3
69
70 conn = sqlite3.connect(filename)
71
72 for card in cards:
73 c = conn.execute(
74 'INSERT INTO Subscriber ' +
75 '(imsi, name, extension, authorized, created, updated) ' +
76 'VALUES ' +
77 '(?,?,?,1,datetime(\'now\'),datetime(\'now\'));',
78 [
79 card.imsi,
80 '%s #%d' % (network.name, card.num),
81 '9%05d' % card.num,
82 ],
83 )
84 sub_id = c.lastrowid
85 c.close()
86
87 c = conn.execute(
88 'INSERT INTO AuthKeys ' +
89 '(subscriber_id, algorithm_id, a3a8_ki)' +
90 'VALUES ' +
91 '(?,?,?)',
92 [ sub_id, 2, sqlite3.Binary(_dbi_binary_quote(h2b(card.ki))) ],
93 )
94 c.close()
95
96 conn.commit()
97 conn.close()
98
99
100#
101# CSV Writing
102#
103
104def csv_write_cards(filename, network, cards):
105 import csv
106 fh = open(filename, 'a')
107 cw = csv.writer(fh)
108 cw.writerows(cards)
109 fh.close()
110
111
112#
113# Main stuff
114#
115
116def parse_options():
117
118 parser = OptionParser(usage="usage: %prog [options]")
119
120 # Network parameters
121 parser.add_option("-n", "--name", dest="name",
122 help="Operator name [default: %default]",
123 default="CCC Event",
124 )
125 parser.add_option("-c", "--country", dest="country", type="int", metavar="CC",
126 help="Country code [default: %default]",
127 default=49,
128 )
129 parser.add_option("-x", "--mcc", dest="mcc", type="int",
130 help="Mobile Country Code [default: %default]",
131 default=262,
132 )
133 parser.add_option("-y", "--mnc", dest="mnc", type="int",
134 help="Mobile Network Code [default: %default]",
135 default=42,
136 )
137 parser.add_option("-m", "--smsp", dest="smsp",
138 help="SMSP [default: '00 + country code + 5555']",
139 )
140
141 # Autogen
142 parser.add_option("-z", "--secret", dest="secret", metavar="STR",
143 help="Secret used for ICCID/IMSI autogen",
144 )
145 parser.add_option("-k", "--count", dest="count", type="int", metavar="CNT",
146 help="Number of entried to generate [default: %default]",
147 default=1000,
148 )
149
150 # Output
151 parser.add_option("--state", dest="state_file", metavar="FILE",
152 help="Use this state file",
153 )
154 parser.add_option("--write-csv", dest="write_csv", metavar="FILE",
155 help="Append generated parameters in CSV file",
156 )
157 parser.add_option("--write-hlr", dest="write_hlr", metavar="FILE",
158 help="Append generated parameters to OpenBSC HLR sqlite3",
159 )
160
161 (options, args) = parser.parse_args()
162
163 if args:
164 parser.error("Extraneous arguments")
165
166 # Check everything
167 if 1 < len(options.name) > 16:
168 parser.error("Name must be between 1 and 16 characters")
169
170 if 0 < options.country > 999:
171 parser.error("Invalid country code")
172
173 if 0 < options.mcc > 999:
174 parser.error("Invalid Mobile Country Code (MCC)")
175 if 0 < options.mnc > 999:
176 parser.error("Invalid Mobile Network Code (MNC)")
177
178 if options.smsp is not None:
179 if not isnum(options.smsp):
180 parser.error("Invalid SMSP Number")
181 else:
182 options.smsp = '00%d' % options.country + '5555'
183
184 return options
185
186
187def main():
188
189 # Parse options
190 opts = parse_options()
191
192 # Load state
193 sm = StateManager(opts.state_file, opts)
194 sm.load()
195
196 # Instanciate generator
197 np = sm.network
198 cpg = CardParametersGenerator(np.cc, np.mcc, np.mnc, sm.get_secret())
199
200 # Generate cards
201 imsis = set()
202 cards = []
203 while len(cards) < opts.count:
204 # Next number
205 i = sm.next_gen_num()
206
207 # Generate card number
208 cp = cpg.generate(i)
209
210 # Check for dupes
211 if cp.imsi in imsis:
212 continue
213 imsis.add(cp.imsi)
214
215 # Collect
216 cards.append(cp)
217
218 # Save cards
219 if opts.write_hlr:
220 hlr_write_cards(opts.write_hlr, np, cards)
221
222 if opts.write_csv:
223 csv_write_cards(opts.write_csv, np, cards)
224
225 # Save state
226 sm.save()
227
228
229if __name__ == '__main__':
230 main()