libnfc  1.7.0-rc7
nfc-relay.c
Go to the documentation of this file.
1 /*-
2  * Free/Libre Near Field Communication (NFC) library
3  *
4  * Libnfc historical contributors:
5  * Copyright (C) 2009 Roel Verdult
6  * Copyright (C) 2009-2013 Romuald Conty
7  * Copyright (C) 2010-2012 Romain Tartière
8  * Copyright (C) 2010-2013 Philippe Teuwen
9  * Copyright (C) 2012-2013 Ludovic Rousseau
10  * Additional contributors of this file:
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  * 1) Redistributions of source code must retain the above copyright notice,
15  * this list of conditions and the following disclaimer.
16  * 2 )Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in the
18  * documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  * Note that this license only applies on the examples, NFC library itself is under LGPL
33  *
34  */
35 
41 #ifdef HAVE_CONFIG_H
42 # include "config.h"
43 #endif /* HAVE_CONFIG_H */
44 
45 #include <inttypes.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <stdint.h>
49 #include <string.h>
50 #include <signal.h>
51 
52 #include <nfc/nfc.h>
53 
54 #include "utils/nfc-utils.h"
55 
56 #define MAX_FRAME_LEN 264
57 #define MAX_DEVICE_COUNT 2
58 
59 static uint8_t abtReaderRx[MAX_FRAME_LEN];
60 static uint8_t abtReaderRxPar[MAX_FRAME_LEN];
61 static int szReaderRxBits;
62 static uint8_t abtTagRx[MAX_FRAME_LEN];
63 static uint8_t abtTagRxPar[MAX_FRAME_LEN];
64 static int szTagRxBits;
65 static nfc_device *pndReader;
66 static nfc_device *pndTag;
67 static bool quitting = false;
68 
69 static void
70 intr_hdlr(int sig)
71 {
72  (void) sig;
73  printf("\nQuitting...\n");
74  quitting = true;
75  return;
76 }
77 
78 static void
79 print_usage(char *argv[])
80 {
81  printf("Usage: %s [OPTIONS]\n", argv[0]);
82  printf("Options:\n");
83  printf("\t-h\tHelp. Print this message.\n");
84  printf("\t-q\tQuiet mode. Suppress output of READER and EMULATOR data (improves timing).\n");
85 }
86 
87 int
88 main(int argc, char *argv[])
89 {
90  int arg;
91  bool quiet_output = false;
92  const char *acLibnfcVersion = nfc_version();
93 
94  // Get commandline options
95  for (arg = 1; arg < argc; arg++) {
96  if (0 == strcmp(argv[arg], "-h")) {
97  print_usage(argv);
98  exit(EXIT_SUCCESS);
99  } else if (0 == strcmp(argv[arg], "-q")) {
100  quiet_output = true;
101  } else {
102  ERR("%s is not supported option.", argv[arg]);
103  print_usage(argv);
104  exit(EXIT_FAILURE);
105  }
106  }
107 
108  // Display libnfc version
109  printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
110 
111 #ifdef WIN32
112  signal(SIGINT, (void (__cdecl *)(int)) intr_hdlr);
113 #else
114  signal(SIGINT, intr_hdlr);
115 #endif
116 
117  nfc_context *context;
118  nfc_init(&context);
119  if (context == NULL) {
120  ERR("Unable to init libnfc (malloc)");
121  exit(EXIT_FAILURE);
122  }
123  nfc_connstring connstrings[MAX_DEVICE_COUNT];
124  // List available devices
125  size_t szFound = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT);
126 
127  if (szFound < 2) {
128  ERR("%" PRIdPTR " device found but two opened devices are needed to relay NFC.", szFound);
129  nfc_exit(context);
130  exit(EXIT_FAILURE);
131  }
132 
133  // Try to open the NFC emulator device
134  pndTag = nfc_open(context, connstrings[0]);
135  if (pndTag == NULL) {
136  ERR("Error opening NFC emulator device");
137  nfc_exit(context);
138  exit(EXIT_FAILURE);
139  }
140 
141  printf("Hint: tag <---> initiator (relay) <---> target (relay) <---> original reader\n\n");
142 
143  printf("NFC emulator device: %s opened\n", nfc_device_get_name(pndTag));
144  printf("[+] Try to break out the auto-emulation, this requires a second reader!\n");
145  printf("[+] To do this, please send any command after the anti-collision\n");
146  printf("[+] For example, send a RATS command or use the \"nfc-anticol\" tool\n");
147 
148  nfc_target nt = {
149  .nm = {
150  .nmt = NMT_ISO14443A,
151  .nbr = NBR_UNDEFINED,
152  },
153  .nti = {
154  .nai = {
155  .abtAtqa = { 0x04, 0x00 },
156  .abtUid = { 0x08, 0xad, 0xbe, 0xef },
157  .btSak = 0x20,
158  .szUidLen = 4,
159  .szAtsLen = 0,
160  },
161  },
162  };
163 
164  if ((szReaderRxBits = nfc_target_init(pndTag, &nt, abtReaderRx, sizeof(abtReaderRx), 0)) < 0) {
165  ERR("%s", "Initialization of NFC emulator failed");
166  nfc_close(pndTag);
167  nfc_exit(context);
168  exit(EXIT_FAILURE);
169  }
170  printf("%s", "Configuring emulator settings...");
171  if ((nfc_device_set_property_bool(pndTag, NP_HANDLE_CRC, false) < 0) ||
173  nfc_perror(pndTag, "nfc_device_set_property_bool");
174  nfc_close(pndTag);
175  nfc_exit(context);
176  exit(EXIT_FAILURE);
177  }
178  printf("%s", "Done, emulated tag is initialized");
179 
180  // Try to open the NFC reader
181  pndReader = nfc_open(context, connstrings[1]);
182  if (pndReader == NULL) {
183  printf("Error opening NFC reader device\n");
184  nfc_close(pndTag);
185  nfc_exit(context);
186  exit(EXIT_FAILURE);
187  }
188 
189  printf("NFC reader device: %s opened", nfc_device_get_name(pndReader));
190  printf("%s", "Configuring NFC reader settings...");
191 
192  if (nfc_initiator_init(pndReader) < 0) {
193  nfc_perror(pndReader, "nfc_initiator_init");
194  nfc_close(pndTag);
195  nfc_close(pndReader);
196  nfc_exit(context);
197  exit(EXIT_FAILURE);
198  }
199  if ((nfc_device_set_property_bool(pndReader, NP_HANDLE_CRC, false) < 0) ||
200  (nfc_device_set_property_bool(pndReader, NP_HANDLE_PARITY, false) < 0) ||
201  (nfc_device_set_property_bool(pndReader, NP_ACCEPT_INVALID_FRAMES, true)) < 0) {
202  nfc_perror(pndReader, "nfc_device_set_property_bool");
203  nfc_close(pndTag);
204  nfc_close(pndReader);
205  nfc_exit(context);
206  exit(EXIT_FAILURE);
207  }
208  printf("%s", "Done, relaying frames now!");
209 
210  while (!quitting) {
211  // Test if we received a frame from the reader
212  if ((szReaderRxBits = nfc_target_receive_bits(pndTag, abtReaderRx, sizeof(abtReaderRx), abtReaderRxPar)) > 0) {
213  // Drop down the field before sending a REQA command and start a new session
214  if (szReaderRxBits == 7 && abtReaderRx[0] == 0x26) {
215  // Drop down field for a very short time (original tag will reboot)
216  if (nfc_device_set_property_bool(pndReader, NP_ACTIVATE_FIELD, false) < 0) {
217  nfc_perror(pndReader, "nfc_device_set_property_bool");
218  nfc_close(pndTag);
219  nfc_close(pndReader);
220  nfc_exit(context);
221  exit(EXIT_FAILURE);
222  }
223  if (!quiet_output)
224  printf("\n");
225  if (nfc_device_set_property_bool(pndReader, NP_ACTIVATE_FIELD, true) < 0) {
226  nfc_perror(pndReader, "nfc_device_set_property_bool");
227  nfc_close(pndTag);
228  nfc_close(pndReader);
229  nfc_exit(context);
230  exit(EXIT_FAILURE);
231  }
232  }
233  // Print the reader frame to the screen
234  if (!quiet_output) {
235  printf("R: ");
236  print_hex_par(abtReaderRx, (size_t) szReaderRxBits, abtReaderRxPar);
237  }
238  // Forward the frame to the original tag
239  if ((szTagRxBits = nfc_initiator_transceive_bits
240  (pndReader, abtReaderRx, (size_t) szReaderRxBits, abtReaderRxPar, abtTagRx, sizeof(abtTagRx), abtTagRxPar)) > 0) {
241  // Redirect the answer back to the reader
242  if (nfc_target_send_bits(pndTag, abtTagRx, szTagRxBits, abtTagRxPar) < 0) {
243  nfc_perror(pndTag, "nfc_target_send_bits");
244  nfc_close(pndTag);
245  nfc_close(pndReader);
246  nfc_exit(context);
247  exit(EXIT_FAILURE);
248  }
249  // Print the tag frame to the screen
250  if (!quiet_output) {
251  printf("T: ");
252  print_hex_par(abtTagRx, szTagRxBits, abtTagRxPar);
253  }
254  }
255  }
256  }
257 
258  nfc_close(pndTag);
259  nfc_close(pndReader);
260  nfc_exit(context);
261  exit(EXIT_SUCCESS);
262 }